;;; ;;; graph.lisp ;;; ;;; Created: 2003-12-22 by Zach Beane ;;; ;;; **PURPOSE** ;;; ;;; ;;; $Id$ (defpackage "ASDF-GRAPH" (:use "CL")) (in-package "ASDF-GRAPH") (defvar *load-op* (make-instance 'asdf::load-op)) (defun maybe-quote (string) "If STRING contains non-identifier characters, return it surrounded by double-quotes, otherwise return it directly." (if (or (find #\- string) (find #\/ string)) (format nil "\"~A\"" string) string)) (defun node-name (string) (maybe-quote (if *node-prefix* (format nil "~A_~A" *node-prefix* string) string))) (defmethod dependencies (item) nil) (defmethod dependencies ((item asdf::component)) (let ((depend-operation-list (cdr (asdf:component-depends-on *load-op* item)))) (when depend-operation-list (let ((deps nil)) (dolist (depend-op depend-operation-list deps) (dolist (component (cdr depend-op)) (when (stringp component) (push component deps)))))))) (defun make-edge (from to) (format t "~&~A -> ~A;~%" (node-name from) (node-name to))) (defvar *node-prefix* nil) (defun make-node (name &key (shape nil)) (format t "~&~A [label=\"~A\"" (node-name name) name) (when shape (format t ",shape=~A" shape)) (format t "];~%")) (defmacro with-subgraph (name &body body) (let ((subgraph-name (gensym))) `(let* ((,subgraph-name ,name) (*node-prefix* ,subgraph-name)) (format t "~&subgraph \"cluster~A\" {~%" ,subgraph-name) (format t "label=\"~A\";~%" ,subgraph-name) ,@body (format t "~&};~%")))) (defgeneric dot-graph (item)) (defmethod dot-graph ((item asdf::system)) (format t "~&digraph ~A {~%" (maybe-quote (asdf:component-name item))) (format t "rankdir=LR;~%") (dolist (component (asdf:module-components item)) (dot-graph component)) (format t "~&}~%")) (defmethod dot-graph ((item asdf::module)) (let ((name (asdf:component-name item))) (make-node name :shape "box") (with-subgraph name (dolist (component (asdf:module-components item)) (dot-graph component))))) (defmethod dot-graph ((item asdf::component)) (let ((name (asdf:component-name item))) (make-node name) (dolist (dep (dependencies item)) (make-edge name dep)))) (defun make-dot-file (system-name) (let ((system (asdf:find-system system-name nil)) (output-file (format nil "~A.dot" system-name))) (when system (with-open-file (*standard-output* output-file :direction :output) (dot-graph system)) (format t "; wrote ~A~%" output-file))))