From 6ae48d6d28112d487ea09ca905814da47c2a26cf 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--dependencies): Extend function to handle and return package descriptors. (package-isolate): Add new command. * etc/NEWS: Announce new command. --- etc/NEWS | 6 ++++ lisp/emacs-lisp/package.el | 57 ++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) 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..9e969ce1024 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -2330,12 +2330,26 @@ package-upgrade-all (mapc #'package-upgrade upgradeable)))) (defun package--dependencies (pkg) - "Return a list of all dependencies PKG has. -This is done recursively." - ;; Can we have circular dependencies? Assume "nope". - (when-let* ((desc (cadr (assq pkg package-archive-contents))) - (deps (mapcar #'car (package-desc-reqs desc)))) - (delete-dups (apply #'nconc deps (mapcar #'package--dependencies deps))))) + "Return a list of all recursive dependencies of PKG. +If PKG is a package descriptor, the return value will consist of +a list of package descriptors. If PKG is a symbol, designating a +package, the return value will be a list of symbols designating +packages." + (when-let* ((desc (if (package-desc-p pkg) pkg + (cadr (assq pkg package-archive-contents))))) + ;; Can we have circular dependencies? Assume "nope". + (let ((all (named-let more ((pkg-desc desc)) + (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 (more p))))) + deps))) + (delete-dups (cons pkg-desc deps)))))) + (remq pkg (mapcar (if (package-desc-p pkg) #'identity #'package-desc-name) all))))) (defun package-strip-rcs-id (str) "Strip RCS version ID from the version string STR. @@ -2625,6 +2639,37 @@ 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=))))) + (let* ((name (concat "package-isolate-" + (mapconcat #'package-desc-full-name packages ","))) + package-load-list) + (dolist (package (append packages (mapcan #'package--dependencies packages))) + (push (list (package-desc-name package) + (package-version-join (package-desc-version package))) + package-load-list)) + (apply #'start-process (concat "*" name "*") nil + (list (expand-file-name invocation-name invocation-directory) + "--quick" "--debug-init" + "--init-directory" (make-temp-file name t) + (format "--eval=%S" + `(progn + (require 'warnings) + (add-to-list 'warning-suppress-log-types 'initialization) + (require 'package) + (setq package-user-dir ,(expand-file-name package-user-dir) + package-load-list ',package-load-list) + (package-initialize))))))) + ;;;; Package description buffer. -- 2.39.2