api-diff.scm 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. ;;; api-diff --- diff guile-api.alist files
  2. ;; Copyright (C) 2002, 2006, 2011 Free Software Foundation, Inc.
  3. ;;
  4. ;; This program is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU Lesser General Public License
  6. ;; as published by the Free Software Foundation; either version 3, or
  7. ;; (at your option) any later version.
  8. ;;
  9. ;; This program is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Lesser General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Lesser General Public
  15. ;; License along with this software; see the file COPYING.LESSER. If
  16. ;; not, write to the Free Software Foundation, Inc., 51 Franklin
  17. ;; Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. ;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
  19. ;;; Commentary:
  20. ;; Usage: api-diff [-d GROUPS] ALIST-FILE-A ALIST-FILE-B
  21. ;;
  22. ;; Read in the alists from files ALIST-FILE-A and ALIST-FILE-B
  23. ;; and display a (count) summary of the groups defined therein.
  24. ;; Optional arg "--details" (or "-d") specifies a comma-separated
  25. ;; list of groups, in which case api-diff displays instead the
  26. ;; elements added and deleted for each of the specified groups.
  27. ;;
  28. ;; For scheme programming, this module exports the proc:
  29. ;; (api-diff A-file B-file)
  30. ;;
  31. ;; Note that the convention is that the "older" alist/file is
  32. ;; specified first.
  33. ;;
  34. ;; TODO: Develop scheme interface.
  35. ;;; Code:
  36. (define-module (scripts api-diff)
  37. :use-module (ice-9 common-list)
  38. :use-module (ice-9 format)
  39. :use-module (ice-9 getopt-long)
  40. :autoload (srfi srfi-13) (string-tokenize)
  41. :export (api-diff))
  42. (define %include-in-guild-list #f)
  43. (define %summary "Show differences between two scan-api files.")
  44. (define (read-alist-file file)
  45. (with-input-from-file file
  46. (lambda () (read))))
  47. (define put set-object-property!)
  48. (define get object-property)
  49. (define (read-api-alist-file file)
  50. (let* ((alist (read-alist-file file))
  51. (meta (assq-ref alist 'meta))
  52. (interface (assq-ref alist 'interface)))
  53. (put interface 'meta meta)
  54. (put interface 'groups (let ((ht (make-hash-table 31)))
  55. (for-each (lambda (group)
  56. (hashq-set! ht group '()))
  57. (assq-ref meta 'groups))
  58. ht))
  59. interface))
  60. (define (hang-by-the-roots interface)
  61. (let ((ht (get interface 'groups)))
  62. (for-each (lambda (x)
  63. (for-each (lambda (group)
  64. (hashq-set! ht group
  65. (cons (car x)
  66. (hashq-ref ht group))))
  67. (assq-ref x 'groups)))
  68. interface))
  69. interface)
  70. (define (diff? a b)
  71. (let ((result (set-difference a b)))
  72. (if (null? result)
  73. #f ; CL weenies bite me
  74. result)))
  75. (define (diff+note! a b note-removals note-additions note-same)
  76. (let ((same? #t))
  77. (cond ((diff? a b) => (lambda (x) (note-removals x) (set! same? #f))))
  78. (cond ((diff? b a) => (lambda (x) (note-additions x) (set! same? #f))))
  79. (and same? (note-same))))
  80. (define (group-diff i-old i-new . options)
  81. (let* ((i-old (hang-by-the-roots i-old))
  82. (g-old (hash-fold acons '() (get i-old 'groups)))
  83. (g-old-names (map car g-old))
  84. (i-new (hang-by-the-roots i-new))
  85. (g-new (hash-fold acons '() (get i-new 'groups)))
  86. (g-new-names (map car g-new)))
  87. (cond ((null? options)
  88. (diff+note! g-old-names g-new-names
  89. (lambda (removals)
  90. (format #t "groups-removed: ~A\n" removals))
  91. (lambda (additions)
  92. (format #t "groups-added: ~A\n" additions))
  93. (lambda () #t))
  94. (for-each (lambda (group)
  95. (let* ((old (assq-ref g-old group))
  96. (new (assq-ref g-new group))
  97. (old-count (and old (length old)))
  98. (new-count (and new (length new)))
  99. (delta (and old new (- new-count old-count))))
  100. (format #t " ~5@A ~5@A : "
  101. (or old-count "-")
  102. (or new-count "-"))
  103. (cond ((and old new)
  104. (let ((add-count 0) (sub-count 0))
  105. (diff+note!
  106. old new
  107. (lambda (subs)
  108. (set! sub-count (length subs)))
  109. (lambda (adds)
  110. (set! add-count (length adds)))
  111. (lambda () #t))
  112. (format #t "~5@D ~5@D : ~5@D"
  113. add-count (- sub-count) delta)))
  114. (else
  115. (format #t "~5@A ~5@A : ~5@A" "-" "-" "-")))
  116. (format #t " ~A\n" group)))
  117. (sort (union g-old-names g-new-names)
  118. (lambda (a b)
  119. (string<? (symbol->string a)
  120. (symbol->string b))))))
  121. ((assq-ref options 'details)
  122. => (lambda (groups)
  123. (for-each (lambda (group)
  124. (let* ((old (or (assq-ref g-old group) '()))
  125. (new (or (assq-ref g-new group) '()))
  126. (>>! (lambda (label ls)
  127. (format #t "~A ~A:\n" group label)
  128. (for-each (lambda (x)
  129. (format #t " ~A\n" x))
  130. ls))))
  131. (diff+note! old new
  132. (lambda (removals)
  133. (>>! 'removals removals))
  134. (lambda (additions)
  135. (>>! 'additions additions))
  136. (lambda ()
  137. (format #t "~A: no changes\n"
  138. group)))))
  139. groups)))
  140. (else
  141. (error "api-diff: group-diff: bad options")))))
  142. (define (api-diff . args)
  143. (let* ((p (getopt-long (cons 'api-diff args)
  144. '((details (single-char #\d)
  145. (value #t))
  146. ;; Add options here.
  147. )))
  148. (rest (option-ref p '() '("/dev/null" "/dev/null")))
  149. (i-old (read-api-alist-file (car rest)))
  150. (i-new (read-api-alist-file (cadr rest)))
  151. (options '()))
  152. (cond ((option-ref p 'details #f)
  153. => (lambda (groups)
  154. (set! options (cons (cons 'details
  155. (map string->symbol
  156. (string-tokenize
  157. groups
  158. #\,)))
  159. options)))))
  160. (apply group-diff i-old i-new options)))
  161. (define main api-diff)
  162. ;;; api-diff ends here