From ae254f69f789ab4fa2b83bcf2cdc64291ae8aff6 Mon Sep 17 00:00:00 2001 From: Philip Kaludercic Date: Tue, 15 Aug 2023 18:39:14 +0200 Subject: [PATCH 2/2] Add command to start Emacs with specific packages * lisp/emacs-lisp/package.el (package-isolate): Add command. * etc/NEWS: Announce it. --- etc/NEWS | 6 +++++ lisp/emacs-lisp/package.el | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 57f04609679..c374695a571 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -505,6 +505,12 @@ project, that you can quickly select using 'project-switch-project' When non-nil, package specifications with side-effects for building software will be used when building a package. +--- +*** New command to start Emacs only with specific packages +The command 'package-isolate' is equivalent to starting Emacs with the +-Q flag and loading specific packages (and their dependencies) +manually. + ** Flymake +++ diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index b3062d2608b..c0bbdacec84 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -2625,6 +2625,56 @@ package-autoremove removable)) (message "Nothing to autoremove"))))) +(defun package-isolate (packages) + "Start a new instance of Emacs and load only PACKAGES." + (interactive + (cl-loop for p in (cl-loop for p in (package--alist) append (cdr p)) + 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 + "Isolate packages: " table + nil t) + collect (alist-get c table nil nil #'string=)) + current-prefix-arg))) + (cl-assert (cl-every #'package-desc-p packages)) + (let* ((name (concat "package-isolate-" (mapconcat #'package-desc-full-name + packages ","))) + (tmp-init (make-temp-file name t)) + (elpa (expand-file-name "elpa" tmp-init)) + args) + (make-directory elpa) + (dolist (package packages) + ;; We need to recursively expand all the dependencies of the + ;; requested packages and all of them to `load-path'. + (dolist (package (named-let loop ((pkg-desc package)) + (let (deps) + (dolist (req (package-desc-reqs pkg-desc)) + (setq deps (nconc + (catch 'found + (dolist (p (apply #'append (mapcar #'cdr (package--alist)))) + (when (and (string= (car req) (package-desc-name p)) + (version-list-<= (cadr req) (package-desc-version p))) + (throw 'found (loop p))))) + deps))) + (cons pkg-desc deps)))) + (let* ((real (package-desc-dir package)) + (link (expand-file-name (file-name-nondirectory real) elpa))) + (make-symbolic-link real link t) + (push (format "--directory=%s" link) args)) + (let* ((load-suffixes '(".el" ".elc")) + (autoload (locate-library (package--autoloads-file-name package)))) + (push (format "--load=%s" autoload) args)))) + (apply #'start-process (concat "*" name "*") nil + (append (list (or (emacs-executable) "emacs") + (format "--eval=%S" + '(progn + (require 'warnings) + (add-to-list 'warning-suppress-log-types 'initialization))) + "--quick" "--debug-init" + "--init-directory" tmp-init) + args)))) + ;;;; Package description buffer. -- 2.39.2