3
$Id: logmer.scm,v 1.27 2000/08/20 04:08:56 cph Exp $
5
Copyright (c) 1988-2000 Massachusetts Institute of Technology
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or (at
10
your option) any later version.
12
This program is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
(declare (usual-integrations))
26
(define (rcs-directory-log directory #!optional options)
27
(let ((options (if (default-object? options) '() options))
28
(port (notification-output-port)))
29
(let ((changelog? (find-option options 'CHANGELOG? #f)))
31
(merge-pathnames (or (find-option options 'OUTPUT-FILE #f)
32
(if changelog? "ChangeLog" "RCS.log"))
33
(pathname-as-directory directory))))
35
(write-string "regenerating log for directory: " port)
36
(write (->namestring directory))
37
(write-string "..." port)
38
(let ((pathnames (rcs-directory-read directory)))
39
(if (let ((time (file-modification-time-indirect output-file)))
41
(there-exists? pathnames
43
(> (file-modification-time-indirect (cdr w.r))
47
(write-string "total files: " port)
48
(write (length pathnames) port)
50
(let ((entries (read-entries pathnames port)))
51
(write-string "total entries: " port)
52
(write (length entries) port)
56
(sort-entries-for-changelog entries)
57
(sort-entries-for-rcs.log entries))))
58
(write-string "sorting finished" port)
60
(call-with-output-file output-file
63
(format-changelog entries options port)
64
(format-rcs.log entries options port)))))))
66
(write-string " log is up to date" port)
69
(define (find-option options key default)
70
(let loop ((options options))
72
(if (eq? key (caar options))
79
(define (format-rcs.log entries options port)
81
(let ((groups (group-entries-by-log entries))
84
(for-each (lambda (entry)
85
(let ((delta (car entry))
86
(filename (cdr entry)))
87
(write-string "file: " port)
88
(write-string filename port)
89
(write-string "; revision: " port)
90
(write-string (delta/number delta) port)
91
(write-string "\ndate: " port)
92
(write-string (date->string (delta/date delta)) port)
93
(write-string "; author: " port)
94
(write-string (delta/author delta) port)
98
(write-string (delta/log (car (car group))) port)
102
(format-group (car groups))
103
(for-each (lambda (group)
104
(write-string "----------------------------" port)
106
(format-group group))
109
(define (sort-entries-for-rcs.log entries)
112
(date<? (delta/date (car y)) (delta/date (car x))))))
114
;;;; ChangeLog format
116
(define (format-changelog entries options port)
118
(group-entries-by-author&day
119
(list-transform-negative entries
121
(string-prefix? "#" (delta/log (car entry))))))))
124
(or (find-option options 'CHANGELOG-MAP #f)
125
(list (os/hostname)))))
126
(format-changelog-group (car groups) changelog-map options port)
127
(for-each (lambda (group)
129
(format-changelog-group group changelog-map options
133
(define (format-changelog-group entries changelog-map options port)
134
(write-string (format-date-for-changelog (delta/date (caar entries))) port)
135
(write-string " " port)
136
(let ((author (delta/author (caar entries))))
137
(let ((mentry (assoc author (cdr changelog-map))))
138
(write-string (if mentry (cadr mentry) author) port)
139
(write-string " <" port)
140
(if (and mentry (pair? (cddr mentry)))
141
(write-string (caddr mentry) port)
143
(write-string author port)
144
(write-string "@" port)
145
(write-string (car changelog-map) port)))
146
(write-string ">" port)))
151
(write-char #\tab port)
152
(write-string "* " port)
154
(if (find-option options 'SHOW-VERSIONS #t)
156
(string-append (cdr entry)
157
"[" (delta/number (car entry)) "]"))
158
(sort-group-by-name&date entries))
159
(remove-duplicate-strings (sort (map cdr entries) string<?)))))
160
(write-string (car filenames) port)
162
((filenames (cdr filenames))
163
(column (fix:+ 11 (string-length (car filenames)))))
164
(if (pair? filenames)
165
(let ((filename (car filenames)))
166
(let ((column* (+ column 2 (string-length filename))))
167
(if (fix:>= column* 80)
169
(write-string "," port)
171
(write-char #\tab port)
172
(write-string " " port)
173
(write-string filename port)
174
(loop (cdr filenames)
175
(fix:+ 11 (string-length filename))))
177
(write-string ", " port)
178
(write-string filename port)
179
(loop (cdr filenames) column*))))))))
180
(write-string ":" port)
182
(format-log-for-changelog (delta/log (caar entries)) port))
183
(sort-groups-by-date (group-entries-by-log entries))))
185
(define (sort-entries-for-changelog entries)
188
(or (day>? (delta/date (car x)) (delta/date (car y)))
189
(and (day=? (delta/date (car x)) (delta/date (car y)))
190
(or (string<? (delta/author (car x))
191
(delta/author (car y)))
192
(and (string=? (delta/author (car x))
193
(delta/author (car y)))
194
(string<? (delta/log (car x))
195
(delta/log (car y))))))))))
197
(define (sort-group-by-name&date entries)
200
(or (string<? (cdr x) (cdr y))
201
(and (string=? (cdr x) (cdr y))
202
(date>? (delta/date (car x)) (delta/date (car y))))))))
204
(define (format-date-for-changelog date)
205
(let ((dt (date/decoded date)))
207
(number->string (decoded-time/year dt))
209
(string-pad-left (number->string (decoded-time/month dt)) 2 #\0)
211
(string-pad-left (number->string (decoded-time/day dt)) 2 #\0))))
213
(define (format-log-for-changelog log port)
214
(write-char #\tab port)
215
(let ((end (string-length log)))
216
(let loop ((start 0))
217
(let ((index (substring-find-next-char log start end #\newline)))
219
(let ((index (fix:+ index 1)))
220
(write-substring log start index port)
221
(if (fix:< index end)
223
(write-char #\tab port)
226
(write-substring log start end port)
229
(define (remove-duplicate-strings strings)
230
;; Assumes that STRINGS is sorted.
231
(let loop ((strings strings) (result '()))
234
(if (and (pair? (cdr strings))
235
(string=? (car strings) (cadr strings)))
237
(cons (car strings) result)))
240
(define (sort-groups-by-date groups)
244
((entries (cdr entries))
245
(winner (caar entries)))
248
(if (date<? (delta/date (caar entries))
254
(date>? (delta/date x) (delta/date y)))))
256
(define (sort-groups groups choose-representative predicate)
258
(sort (map (lambda (group)
259
(cons (choose-representative group) group))
262
(predicate (car x) (car y))))))
264
(define (group-entries-by-author&day entries)
265
(group-entries entries
267
(and (string=? (delta/author (car x)) (delta/author (car y)))
268
(day=? (delta/date (car x)) (delta/date (car y)))))))
270
(define (group-entries-by-log entries)
271
(group-entries entries
273
(string=? (delta/log (car x)) (delta/log (car y))))))
275
(define (group-entries entries predicate)
276
(let outer ((entries entries) (groups '()))
278
(let ((entry (car entries)))
279
(let inner ((entries (cdr entries)) (group (list entry)))
280
(if (and (pair? entries)
281
(predicate entry (car entries)))
282
(inner (cdr entries) (cons (car entries) group))
283
(outer entries (cons (reverse! group) groups)))))
286
(define (read-entries pairs notification-port)
287
(let ((prefix (greatest-common-prefix (map car pairs))))
290
(map (let ((filename (->namestring (enough-pathname (car w.r) prefix))))
292
(cons delta filename)))
293
(read-file (cdr w.r) notification-port)))
296
(define (read-file pathname notification-port)
297
(if notification-port
299
(write-string "read-file " notification-port)
300
(write-string (->namestring pathname) notification-port)
301
(newline notification-port)))
302
(let ((deltas (rcstext->deltas (rcs/read-file pathname 'LOG-ONLY))))
303
(for-each (lambda (delta)
304
(set-delta/log! delta
305
(let ((log (string-trim (delta/log delta))))
306
(if (string-null? log)
310
(list-transform-negative deltas delta/trivial-log?)))
312
(define (delta/trivial-log? delta)
313
(string=? (delta/log delta) "Initial revision"))
315
(define empty-log-message "*** empty log message ***")
317
(define (rcstext->deltas rcstext)
318
(let ((head (rcstext/head rcstext)))
321
(let loop ((input (list head)) (output '()))
324
(let ((input* (append (delta/branches (car input)) (cdr input))))
325
(loop (if (delta/next (car input))
326
(cons (delta/next (car input)) input*)
328
(cons (car input) output))))))))
330
(define (rcs-directory-read pathname)
332
(define (scan-directory cvs-mode? directory original-directory)
333
(let ((directory (pathname-as-directory directory))
334
(original-directory (pathname-as-directory original-directory)))
335
(for-each (lambda (pathname)
338
(merge-pathnames (file-pathname pathname)
339
original-directory)))
340
(directory-read directory #f))))
342
(define (scan-file cvs-mode? pathname original-pathname)
343
(let ((attributes (file-attributes-direct pathname)))
345
(warn "Cannot get attributes. Path might contain stale symlink."
346
(error-irritant/noise "\n; ")
348
(error-irritant/noise "\n; points to\n; ")
350
(let ((type (file-attributes/type attributes)))
352
(if (not (or (ignored-file-name? cvs-mode? pathname)
353
(ignored-file-name? cvs-mode?
355
(let ((file (rcs-files cvs-mode? pathname)))
357
(set! files (cons file files))))))
359
(if (not (member (file-namestring pathname)
360
'("." ".." "CVS" "RCS")))
361
(scan-directory cvs-mode?
362
pathname original-pathname)))
365
(merge-pathnames type
366
(directory-pathname pathname))
367
original-pathname)))))))
369
(define (rcs-files cvs-mode? pathname)
370
(let ((directory (directory-pathname pathname))
371
(name (file-namestring pathname)))
373
(and (string-suffix? ",v" name)
374
(cons (merge-pathnames
375
(string-head name (- (string-length name) 2))
378
(let* ((name (string-append name ",v"))
380
(merge-pathnames name (merge-pathnames "RCS/" directory))))
381
(if (regular-file? p)
383
(let ((p (merge-pathnames name directory)))
384
(and (regular-file? p)
385
(cons pathname p))))))))
387
(define (regular-file? pathname)
388
(let ((attributes (file-attributes pathname)))
390
(not (file-attributes/type attributes)))))
392
(define (ignored-file-name? cvs-mode? pathname)
393
(let ((name (file-namestring pathname)))
394
(or (string-suffix? "~" name)
395
(string-prefix? "#" name)
396
(and (not cvs-mode?) (string-suffix? ",v" name)))))
398
(let ((directory (pathname-as-directory pathname)))
399
(let ((cvs (merge-pathnames "CVS/" directory)))
400
(if (file-directory? cvs)
403
(read-one-line-file (merge-pathnames "Repository" cvs))
404
(pathname-as-directory
405
(strip-cvs-remote-prefix
406
(read-one-line-file (merge-pathnames "Root" cvs)))))))
407
(scan-directory #t pathname pathname))
408
(scan-directory #f pathname pathname))))
411
(define (strip-cvs-remote-prefix string)
413
(re-string-match ":\\(\\(ext\\|.?server\\):[^:]+\\|local\\):"
416
(string-tail string (re-match-end-index 0 regs))
419
(define (read-one-line-file pathname)
420
(call-with-input-file pathname read-line))
422
(define (greatest-common-prefix pathnames)
423
(if (null? pathnames)
425
(let ((prefix 'NONE))
426
(for-each (lambda (pathname)
427
(let ((directory (pathname-directory pathname)))
429
(if (eq? prefix 'NONE)
431
(let common-prefix ((x prefix) (y directory))
434
(equal? (car x) (car y)))
436
(common-prefix (cdr x) (cdr y)))
439
(pathname-new-directory "" prefix))))
b'\\ No newline at end of file'