diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 32200227de..cbb326f26e 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -656,6 +656,8 @@ PKG-DESC is a `package-desc' object." (defvar Info-directory-list) (declare-function info-initialize "info" ()) +(defvar package--fastpath-pkgs t) + (defun package--load-files-for-activation (pkg-desc reload) "Load files for activating a package given by PKG-DESC. Load the autoloads file, and ensure `load-path' is setup. If @@ -696,7 +698,10 @@ correspond to previously loaded files (those returned by (unless (package-activate (car req)) (error "Unable to activate package `%s'.\nRequired package `%s-%s' is unavailable" name (car req) (package-version-join (cadr req)))))) - (package--load-files-for-activation pkg-desc reload) + (if (listp package--fastpath-pkgs) + ;; We're only collecting the set of packages to activate! + (push pkg-desc package--fastpath-pkgs) + (package--load-files-for-activation pkg-desc reload)) ;; Add info node. (when (file-exists-p (expand-file-name "dir" pkg-dir)) ;; FIXME: not the friendliest, but simple. @@ -3437,6 +3442,67 @@ The list is displayed in a buffer named `*Packages*'." (interactive) (list-packages t)) +;;;; Fast-path for activation! + +(defcustom package-fastpath-file (locate-user-emacs-file "package-fastpath.el") + "Location of the file used to speed up activation of packages at startup." + :type 'file) + +(defun package-fastpath-refresh () + "(Re)Generate the `package-fastpath-file'." + (interactive) + (package-initialize 'no-activate) + (require 'info) + (let ((package--fastpath-pkgs ()) + ;; Pretend we haven't activated anything yet! + (package-activated-list ()) + (Info-directory-list '(""))) + (dolist (elt package-alist) + (condition-case err + (package-activate (car elt)) + ;; Don't let failure of activation of a package arbitrarily stop + ;; activation of further packages. + (error (message "%s" (error-message-string err))))) + (setq package--fastpath-pkgs (nreverse package--fastpath-pkgs)) + (with-temp-file package-fastpath-file + (emacs-lisp-mode) + (insert ";;; FastPath file to speed up package activation at startup -*- lexical-binding:t -*-\n") + (insert ";; ¡¡ This file is autogenerated, DO NOT EDIT !!\n\n") + (dolist (pkg package--fastpath-pkgs) + (let* ((file + ;; Prefer uncompiled files (and don't accept .so files). + (let ((load-suffixes '(".el" ".elc"))) + (locate-library (package--autoloads-file-name pkg)))) + (pfile (prin1-to-string file))) + (insert "(let ((load-file-name " pfile "))\n") + (insert-file-contents file) + ;; FIXME: We also need to setup the Info-directory-list! + (while (search-forward "#$" nil 'move) + (unless (nth 8 (syntax-ppss)) + (replace-match pfile t t))) + (unless (bolp) (insert "\n")) + (insert ")\n"))) + (pp `(setq package-activated-list + (append ',(mapcar #'package-desc-name package--fastpath-pkgs) + package-activated-list)) + (current-buffer)) + (let ((info-dirs (butlast Info-directory-list))) + (when info-dirs + (pp `(progn (require 'info) + (info-initialize) + (setq Info-directory-list + (append ',info-dirs Info-directory-list))) + (current-buffer)))) + ;; Use `\s' instead of a space character, so this code chunk is not + ;; mistaken for an actual file-local section of package.el. + (insert " +;; Local\sVariables: +;; version-control: never +;; no-byte-compile: nil +;; no-update-autoloads: t +;; End: +")))) + (provide 'package) ;;; package.el ends here