mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 01:34:21 +00:00
* lisp/emacs-lisp/package.el: Replace this file with... * lisp/emacs-lisp/package/package.el: a stub file and... * lisp/emacs-lisp/package/package-compile.el: * lisp/emacs-lisp/package/package-describe.el: * lisp/emacs-lisp/package/package-elpa.el: * lisp/emacs-lisp/package/package-install.el: * lisp/emacs-lisp/package/package-menu.el: * lisp/emacs-lisp/package/package-quickstart.el: Multiple files. * lisp/emacs-lisp/package-vc.el: Move this file... * lisp/emacs-lisp/package/package-vc.el: to here.
152 lines
6.4 KiB
EmacsLisp
152 lines
6.4 KiB
EmacsLisp
;;; package-quickstart.el --- Accelerating Package Startup -*- lexical-binding: t; -*-
|
||
|
||
;; Copyright (C) 2007-2025 Free Software Foundation, Inc.
|
||
|
||
;; Author: Tom Tromey <tromey@redhat.com>
|
||
;; Daniel Hackney <dan@haxney.org>
|
||
|
||
;; This program is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation, either version 3 of the License, or
|
||
;; (at your option) any later version.
|
||
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
;;; Commentary:
|
||
|
||
;; Activating packages via `package-initialize' is costly: for N installed
|
||
;; packages, it needs to read all N <pkg>-pkg.el files first to decide
|
||
;; which packages to activate, and then again N <pkg>-autoloads.el files.
|
||
;; To speed this up, we precompute a mega-autoloads file which is the
|
||
;; concatenation of all those <pkg>-autoloads.el, so we can activate
|
||
;; all packages by loading this one file (and hence without initializing
|
||
;; package.el).
|
||
|
||
;; Other than speeding things up, this also offers a bootstrap feature:
|
||
;; it lets us activate packages according to `package-load-list' and
|
||
;; `package-user-dir' even before those vars are set.
|
||
|
||
;;; Code:
|
||
|
||
(require 'package-core)
|
||
|
||
(defcustom package-quickstart nil
|
||
"Precompute activation actions to speed up startup.
|
||
This requires the use of `package-quickstart-refresh' every time the
|
||
activations need to be changed, such as when `package-load-list' is modified."
|
||
:type 'boolean
|
||
:version "27.1"
|
||
:group 'package)
|
||
|
||
;;;###autoload
|
||
(defcustom package-quickstart-file
|
||
(locate-user-emacs-file "package-quickstart.el")
|
||
"Location of the file used to speed up activation of packages at startup."
|
||
:type 'file
|
||
:group 'package
|
||
:initialize #'custom-initialize-delay
|
||
:version "27.1")
|
||
|
||
(defun package--quickstart-maybe-refresh ()
|
||
(if package-quickstart
|
||
;; FIXME: Delay refresh in case we're installing/deleting
|
||
;; several packages!
|
||
(package-quickstart-refresh)
|
||
(delete-file (concat package-quickstart-file "c"))
|
||
(delete-file package-quickstart-file)))
|
||
|
||
(defvar package--quickstart-dir nil
|
||
"Set by `package-quickstart-file' to the directory containing it.")
|
||
|
||
(defun package--quickstart-rel (file)
|
||
"Return an expr depending on `package--quickstart-dir' which evaluates to FILE.
|
||
|
||
If FILE is in `package--quickstart-dir', returns an expression that is
|
||
relative to that directory, so if that directory is moved we can still
|
||
find FILE."
|
||
(if (file-in-directory-p file package--quickstart-dir)
|
||
`(file-name-concat package--quickstart-dir ,(file-relative-name file package--quickstart-dir))
|
||
file))
|
||
|
||
(defun package-quickstart-refresh ()
|
||
"(Re)Generate the `package-quickstart-file'."
|
||
(interactive)
|
||
(package-initialize 'no-activate)
|
||
(require 'info)
|
||
(let ((package--quickstart-pkgs ())
|
||
;; Pretend we haven't activated anything yet!
|
||
(package-activated-list ())
|
||
;; Make sure we can load this file without load-source-file-function.
|
||
(coding-system-for-write 'emacs-internal)
|
||
;; Ensure that `pp' and `prin1-to-string' calls further down
|
||
;; aren't truncated.
|
||
(print-length nil)
|
||
(print-level nil)
|
||
(Info-directory-list '(""))
|
||
(package--quickstart-dir nil))
|
||
(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--quickstart-pkgs (nreverse package--quickstart-pkgs))
|
||
(with-temp-file package-quickstart-file
|
||
(emacs-lisp-mode) ;For `syntax-ppss'.
|
||
(insert ";;; Quickstart file to activate all packages at startup -*- lexical-binding:t -*-\n")
|
||
(insert ";; ¡¡ This file is autogenerated by `package-quickstart-refresh', DO NOT EDIT !!\n\n")
|
||
(setq package--quickstart-dir
|
||
(file-name-directory (expand-file-name package-quickstart-file)))
|
||
(pp '(setq package--quickstart-dir
|
||
(file-name-directory (expand-file-name load-file-name)))
|
||
(current-buffer))
|
||
(dolist (pkg package--quickstart-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 (package--quickstart-rel file))))
|
||
(insert "(let* ((load-file-name " pfile ")\
|
||
\(load-true-file-name load-file-name))\n")
|
||
(insert-file-contents file)
|
||
;; Fixup the special #$ reader form and throw away comments.
|
||
(while (re-search-forward "#\\$\\|^;\\(.*\n\\)" nil 'move)
|
||
(unless (ppss-string-terminator (save-match-data (syntax-ppss)))
|
||
(replace-match (if (match-end 1) "" pfile) t t)))
|
||
(unless (bolp) (insert "\n"))
|
||
(insert ")\n")))
|
||
(pp `(defvar package-activated-list) (current-buffer))
|
||
(pp `(setq package-activated-list
|
||
(delete-dups
|
||
(append ',(mapcar #'package-desc-name package--quickstart-pkgs)
|
||
package-activated-list)))
|
||
(current-buffer))
|
||
(let ((info-dirs
|
||
(mapcar #'package--quickstart-rel (butlast Info-directory-list))))
|
||
(when info-dirs
|
||
(pp `(progn (require 'info)
|
||
(info-initialize)
|
||
(setq Info-directory-list
|
||
(append (list . ,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-update-autoloads: t
|
||
;; byte-compile-warnings: (not make-local)
|
||
;; End:
|
||
"))
|
||
;; FIXME: Do it asynchronously in an Emacs subprocess, and
|
||
;; don't show the byte-compiler warnings.
|
||
(byte-compile-file package-quickstart-file)))
|
||
|
||
(provide 'package-quickstart)
|
||
;;; package-quickstart.el ends here
|