From 47dde2be5732ec9dfa153813649e385e0227751e Mon Sep 17 00:00:00 2001 From: Philip Kaludercic Date: Tue, 15 Aug 2023 18:39:14 +0200 Subject: [PATCH] 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 | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 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..838b2823466 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -2625,6 +2625,53 @@ package-autoremove removable)) (message "Nothing to autoremove"))))) +(defun package-isolate (packages) + "Start an uncustomised Emacs and only load a set of 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=))))) + (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)))) + (push (format "--directory=%s" (package-desc-dir package)) 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 (expand-file-name invocation-name invocation-directory) + "--quick" "--debug-init" + (format "--eval=%S" + '(progn + (require 'warnings) + (add-to-list 'warning-suppress-log-types 'initialization))) + "--init-directory" tmp-init) + args)) + (message "Started Emacs with the init directory: %s" tmp-init))) + ;;;; Package description buffer. -- 2.39.2