Function: package-isolate
package-isolate is an interactive and byte-compiled function defined
in package.el.gz.
Signature
(package-isolate PACKAGES &optional TEMP-INIT)
Documentation
Start an uncustomized Emacs and only load a set of PACKAGES.
Interactively, prompt for PACKAGES to load, which should be specified
separated by commas. If called from Lisp, PACKAGES should be a list of
package-desc objects to load. If an element of PACKAGES is not
installed, it will be fetched, but not activated in the current session.
If TEMP-INIT is non-nil, or when invoked with a prefix argument, the
Emacs user directory is set to a temporary directory. This command is
intended for testing Emacs and/or the packages in a clean environment.
Probably introduced at or before Emacs version 30.1.
Key Bindings
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/package.el.gz
(defun package-isolate (packages &optional temp-init)
"Start an uncustomized Emacs and only load a set of PACKAGES.
Interactively, prompt for PACKAGES to load, which should be specified
separated by commas. If called from Lisp, PACKAGES should be a list of
`package-desc' objects to load. If an element of PACKAGES is not
installed, it will be fetched, but not activated in the current session.
If TEMP-INIT is non-nil, or when invoked with a prefix argument, the
Emacs user directory is set to a temporary directory. This command is
intended for testing Emacs and/or the packages in a clean environment."
(interactive
(cl-loop for p in
(cl-loop with installed = (cl-loop for p in (package--alist)
append (cdr p))
for p in (package--archive-contents)
append (cl-loop
for desc in (cdr p)
unless (cl-loop
for idesc in installed thereis
(and (string= (package-desc-name idesc)
(package-desc-name desc))
(equal (package-desc-version idesc)
(package-desc-version desc))
(eq (package-desc-kind idesc)
(package-desc-kind desc))))
collect desc)
into descs
finally return (nconc installed descs))
unless (package-built-in-p p)
collect (cons (package-desc-full-name p) p) into table
finally return
(list
(cl-loop for c in
(completing-read-multiple
"Packages to isolate: " table
nil t)
collect (alist-get c table nil nil #'string=))
current-prefix-arg)))
(let* ((name (concat "package-isolate-"
(mapconcat #'package-desc-full-name packages ",")))
(all-packages
(delete-dups
(nconc
(mapcan
(pcase-lambda (`(,name ,vers))
(and (not (eq name 'emacs))
(not (cl-find name packages :key #'package-desc-name))
(if-let* ((desc (package-get-descriptor
name t
(lambda (desc)
(version-list-<= vers (package-desc-version desc))))))
(list desc)
(error "Failed to find package: (%s %S)" name vers))))
(package--dependencies packages))
packages)))
(all-packages (seq-remove #'package-built-in-p all-packages))
(package-alist (copy-tree package-alist t))
(temp-install-dir nil) initial-scratch-message load-list)
(when-let* ((missing (seq-remove #'package-installed-p all-packages))
(package-user-dir (make-temp-file "package-isolate" t)))
(setq temp-install-dir (list package-user-dir))
;; We bind `package-activate-1' to prevent activating the package
;; in `package-unpack' for this session.
(cl-letf (((symbol-function #'package-activate-1) #'ignore))
(package-download-transaction missing)))
(with-temp-buffer
(insert ";; This is an isolated testing environment, with these packages enabled:\n\n")
(dolist (package all-packages)
(push (list (package-desc-name package)
(package-version-join (package-desc-version package)))
load-list)
(insert ";; - " (package-desc-full-name package))
(unless (memq package packages)
(insert ", dependency"))
(unless (package-installed-p package)
(insert ", downloaded"))
(insert "\n"))
(insert "\n")
(setq initial-scratch-message (buffer-string)))
(apply #'start-process (concat "*" name "*") nil
(list (expand-file-name invocation-name invocation-directory)
"--quick" "--debug-init"
"--init-directory" (if temp-init
(make-temp-file name t)
user-emacs-directory)
(format "--eval=%S"
`(progn
(setq initial-scratch-message ,initial-scratch-message)
(require 'package)
,@(mapcar
(lambda (dir)
`(add-to-list 'package-directory-list ,dir))
(append (list package-user-dir)
temp-install-dir
package-directory-list))
(setq package-load-list ',load-list)
(package--activate-all)))))))