123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- #!/bin/sh
- # aside from this initial boilerplate, this is actually -*- scheme -*- code
- main='(module-ref (resolve-module '\''(scripts api-diff)) '\'main')'
- exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@"
- !#
- ;;; api-diff --- diff guile-api.alist files
- ;; Copyright (C) 2002, 2006 Free Software Foundation, Inc.
- ;;
- ;; This program is free software; you can redistribute it and/or
- ;; modify it under the terms of the GNU General Public License as
- ;; published by the Free Software Foundation; either version 2, or
- ;; (at your option) any later version.
- ;;
- ;; This program is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;; General Public License for more details.
- ;;
- ;; You should have received a copy of the GNU General Public License
- ;; along with this software; see the file COPYING. If not, write to
- ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- ;; Boston, MA 02110-1301 USA
- ;;; Author: Thien-Thi Nguyen <ttn@gnu.org>
- ;;; Commentary:
- ;; Usage: api-diff [-d GROUPS] ALIST-FILE-A ALIST-FILE-B
- ;;
- ;; Read in the alists from files ALIST-FILE-A and ALIST-FILE-B
- ;; and display a (count) summary of the groups defined therein.
- ;; Optional arg "--details" (or "-d") specifies a comma-separated
- ;; list of groups, in which case api-diff displays instead the
- ;; elements added and deleted for each of the specified groups.
- ;;
- ;; For scheme programming, this module exports the proc:
- ;; (api-diff A-file B-file)
- ;;
- ;; Note that the convention is that the "older" alist/file is
- ;; specified first.
- ;;
- ;; TODO: Develop scheme interface.
- ;;; Code:
- (define-module (scripts api-diff)
- :use-module (ice-9 common-list)
- :use-module (ice-9 format)
- :use-module (ice-9 getopt-long)
- :autoload (srfi srfi-13) (string-tokenize)
- :export (api-diff))
- (define (read-alist-file file)
- (with-input-from-file file
- (lambda () (read))))
- (define put set-object-property!)
- (define get object-property)
- (define (read-api-alist-file file)
- (let* ((alist (read-alist-file file))
- (meta (assq-ref alist 'meta))
- (interface (assq-ref alist 'interface)))
- (put interface 'meta meta)
- (put interface 'groups (let ((ht (make-hash-table 31)))
- (for-each (lambda (group)
- (hashq-set! ht group '()))
- (assq-ref meta 'groups))
- ht))
- interface))
- (define (hang-by-the-roots interface)
- (let ((ht (get interface 'groups)))
- (for-each (lambda (x)
- (for-each (lambda (group)
- (hashq-set! ht group
- (cons (car x)
- (hashq-ref ht group))))
- (assq-ref x 'groups)))
- interface))
- interface)
- (define (diff? a b)
- (let ((result (set-difference a b)))
- (if (null? result)
- #f ; CL weenies bite me
- result)))
- (define (diff+note! a b note-removals note-additions note-same)
- (let ((same? #t))
- (cond ((diff? a b) => (lambda (x) (note-removals x) (set! same? #f))))
- (cond ((diff? b a) => (lambda (x) (note-additions x) (set! same? #f))))
- (and same? (note-same))))
- (define (group-diff i-old i-new . options)
- (let* ((i-old (hang-by-the-roots i-old))
- (g-old (hash-fold acons '() (get i-old 'groups)))
- (g-old-names (map car g-old))
- (i-new (hang-by-the-roots i-new))
- (g-new (hash-fold acons '() (get i-new 'groups)))
- (g-new-names (map car g-new)))
- (cond ((null? options)
- (diff+note! g-old-names g-new-names
- (lambda (removals)
- (format #t "groups-removed: ~A\n" removals))
- (lambda (additions)
- (format #t "groups-added: ~A\n" additions))
- (lambda () #t))
- (for-each (lambda (group)
- (let* ((old (assq-ref g-old group))
- (new (assq-ref g-new group))
- (old-count (and old (length old)))
- (new-count (and new (length new)))
- (delta (and old new (- new-count old-count))))
- (format #t " ~5@A ~5@A : "
- (or old-count "-")
- (or new-count "-"))
- (cond ((and old new)
- (let ((add-count 0) (sub-count 0))
- (diff+note!
- old new
- (lambda (subs)
- (set! sub-count (length subs)))
- (lambda (adds)
- (set! add-count (length adds)))
- (lambda () #t))
- (format #t "~5@D ~5@D : ~5@D"
- add-count (- sub-count) delta)))
- (else
- (format #t "~5@A ~5@A : ~5@A" "-" "-" "-")))
- (format #t " ~A\n" group)))
- (sort (union g-old-names g-new-names)
- (lambda (a b)
- (string<? (symbol->string a)
- (symbol->string b))))))
- ((assq-ref options 'details)
- => (lambda (groups)
- (for-each (lambda (group)
- (let* ((old (or (assq-ref g-old group) '()))
- (new (or (assq-ref g-new group) '()))
- (>>! (lambda (label ls)
- (format #t "~A ~A:\n" group label)
- (for-each (lambda (x)
- (format #t " ~A\n" x))
- ls))))
- (diff+note! old new
- (lambda (removals)
- (>>! 'removals removals))
- (lambda (additions)
- (>>! 'additions additions))
- (lambda ()
- (format #t "~A: no changes\n"
- group)))))
- groups)))
- (else
- (error "api-diff: group-diff: bad options")))))
- (define (api-diff . args)
- (let* ((p (getopt-long (cons 'api-diff args)
- '((details (single-char #\d)
- (value #t))
- ;; Add options here.
- )))
- (rest (option-ref p '() '("/dev/null" "/dev/null")))
- (i-old (read-api-alist-file (car rest)))
- (i-new (read-api-alist-file (cadr rest)))
- (options '()))
- (cond ((option-ref p 'details #f)
- => (lambda (groups)
- (set! options (cons (cons 'details
- (map string->symbol
- (string-tokenize
- groups
- #\,)))
- options)))))
- (apply group-diff i-old i-new options)))
- (define main api-diff)
- ;;; api-diff ends here
|