;;; -*- Mode:LISP; Package:USER; Base:10 -*- (defun directory-diff (path other-host &optional recursive) (let ((pname-1 (fs:parse-pathname path)) (pname-2) (dir-1) (dir-2) (subdir-1) (subdir-2) (temp)) (dolist (e '(:name :type :version)) (if (memq (send pname-1 e) '(nil :unspecific)) (setq pname-1 (send pname-1 :new-pathname e :wild)))) (setq pname-2 (send pname-1 :new-pathname :host other-host)) (format t "~&;Directory: ~A " pname-1) (multiple-value-setq (dir-1 subdir-1) (get-dirlist pname-1)) (when (errorp dir-1) (return-from directory-diff (send dir-1 :report standard-output))) (format t "~D file~p.~%" (length dir-1) (length dir-1)) (format t "~&;Directory: ~A " pname-2) (multiple-value-setq (dir-2 subdir-2) (get-dirlist pname-2)) (when (errorp dir-2) (return-from directory-diff (send dir-2 :report standard-output))) (format t "~D file~p.~%" (length dir-2) (length dir-2)) (multiple-value-bind (extra-1 extra-2 conflict-alist) (dirlist-diff dir-1 dir-2) (cond ((and (not extra-1) (not extra-2) (not conflict-alist)) (format t "~&; File Contents identical~%")) ('else (when extra-1 (format t "~&; Extra in ~A~%" pname-1) (dolist (e extra-1) (cond ((setq temp (superceded-p e dir-2)) (format t "~A ; superceded by ~A~%" e temp)) ('else (format t "~A~%" e))))) (when extra-2 (format t "~&; Extra in ~A~%" pname-2) (dolist (e extra-2) (cond ((setq temp (superceded-p e dir-1)) (format t "~A ; superceded by ~A~%" e temp)) ('else (format t "~A~%" e))))) (when conflict-alist (format t "~&; Conflicting files~%") (dolist (e conflict-alist) (format t "~A and ~A differ in ~{~A~^,~}~%" (caar e) (cadar e) (mapcar #'car (cdr e)))))))) (multiple-value-bind (extra-1 extra-2) (dirlist-diff (mapcar #'list subdir-1) (mapcar #'list subdir-2)) (cond ((and (not extra-1) (not extra-2))) ('else (when extra-1 (format t "~&; Extra subdirectories in ~A~%" pname-1) (dolist (e extra-1) (format t "~A~%" e))) (when extra-2 (format t "~&; Extra subdirectories in ~A~%" pname-2) (dolist (e extra-2) (format t "~A~%" e)))))) (when recursive (dolist (d subdir-1) (directory-diff d other-host recursive))))) (defun superceded-p (path dirlist) (let ((name (send path :name)) (type (send path :type)) (version (send path :version)) (max)) (dolist (e dirlist) (cond ((not (and (equalp (send (car e) :name) name) (equalp (send (car e) :type) type) (> (send (car e) :version) version)))) ((not max) (setq max (car e))) ((> (send (car e) :version) (send max :version)) (setq max (car e))))) max)) (defun get-dirlist (x) (condition-case (e) (filter-dirlist x (fs:directory-list x)) (fs:file-not-found e) (fs:directory-not-found e) (error e))) (defun filter-dirlist (x l) (declare (values (files dirs))) (let (files dirs) (dolist (d l) (cond ((not (car d))) ((get d :directory) (push (send (send (car d) :pathname-as-directory) :new-pathname :name (send x :name) :type (send x :type) :version (send x :version)) dirs)) ('else (push d files)))) (values (nreverse files) (nreverse dirs)))) (defun pname-equalp (a b) (dolist (e '(:directory :name :type :version) t) (or (equalp (send a e) (send b e)) (return nil)))) (defun dirlist-diff (d1 d2) (declare (values extra-1 extra-2 conflict-alist)) (let (extra-1 extra-2 conflict-alist) (dolist (f1 d1) (let ((cell (ass #'pname-equalp (car f1) d2))) (cond ((not cell) (push (car f1) extra-1)) ('else (let ((conflicts)) (dolist (e '(:creation-date :author :length-in-bytes :byte-size :characters)) (or (equalp (get f1 e) (get cell e)) (push (list e (get f1 e) (get cell e)) conflicts))) (when conflicts (push (cons (list (car f1) (car cell)) conflicts) conflict-alist))))))) (dolist (f2 d2) (let ((cell (ass #'pname-equalp (car f2) d1))) (cond ((not cell) (push (car f2) extra-2))))) (values extra-1 extra-2 conflict-alist))) (defun compare-machine-dirs (m1 m2 &optional (version :wild)) "look at all dirs on m1 and compare with m2" (let ((alld (mapcar #'car (fs:all-directories m1)))) (format t "~&~D directories on ~A" (length alld) m1) (dolist (d alld) (directory-diff (send d :new-pathname :version version) m2 t))))