;;; Proof of concept: monitoring changes in the Lisp system after loading the code
#|
Main concept code: 
  (let ((old-all-packages (list-all-packages)))
    (load *test-file*)
    (set-difference (list-all-packages) 
		    old-all-packages))
|#

(defparameter *files-packages* (make-hash-table :test 'equal))

(defmacro with-bind-packages-load ((s-new-packages file &optional other-load-args) &body body)
  (let ((s-old-all-packages (gentemp "OLD-ALL-PACKAGES-")))
    `(let ((,s-old-all-packages (list-all-packages))
	   (,s-new-packages nil))
       (apply #'load ,file ,other-load-args)
       (setf ,s-new-packages 
	     (set-difference (list-all-packages) 
			     ,s-old-all-packages))
       ,@body)))

(defun load-observing (file sandbox &rest other-load-args)
  (declare (ignorable other-load-args))
  (with-bind-packages-load (new-packages file other-load-args)
    (loop for pkg in new-packages
       do (setf (gethash pkg sandbox) t)))
  t)

(defmacro with-monitoring-load (file &body body)
  (let ((s-sandbox (gentemp "SANDBOX-")))
    `(let ((,s-sandbox (make-hash-table)))
       (setf (gethash (truename ,file) *files-packages*)
	     ,s-sandbox)
       (load-observing ,file ,s-sandbox)
       ,@body)))

(defun packages-in-file (file &aux packages-hash)
  (setf packages-hash (gethash (truename file) *files-packages*))
  (when packages-hash 
    (loop for pkg being the hash-key in packages-hash
       collect pkg)))

;; Example:
(defparameter *test-file* "somepackages.lisp")

;; Create test file 
(with-open-file (stream *test-file*
			:direction :output 
			:if-exists :supersede 
			:if-does-not-exist :create)
  (princ 
   "(defpackage :pkg1 (:use :cl))
\(defpackage :pkg2 (:use :pkg1))

\(in-package :pkg2)
\(cl:defun hello-from-pkg2 () 'hello-from-pkg2)"
   stream))

(with-monitoring-load *test-file*
  (format t "Loaded packages from ~S: ~A"
	  *test-file*
	  (packages-in-file *test-file*)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Additional: 
(defun delete-packages-in-sandbox (sandbox &optional packages)
  (if packages
      (loop for pkg in packages
	 for used-by = (package-used-by-list pkg)
	 when used-by do (delete-packages-in-sandbox sandbox used-by)
	 if (gethash pkg sandbox) do
	 (format t "~%Package ~S deleting ..." pkg)
	 (delete-package pkg)
	 (format t "~%Package ~S deleted" pkg)
	 (remhash pkg sandbox)
	 else do (error "Package miss into sandbox"))
      (progn 
	(loop for pkg being the hash-key in sandbox
	   do (delete-packages-in-sandbox sandbox (list pkg)))
	(clrhash sandbox))))

;; Example:

(delete-packages-in-sandbox
 (gethash (truename "somepackages.lisp") *files-packages*))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Cleanup
(delete-file *test-file*)