summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/package.el
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2021-01-05 12:28:37 -0500
committerStefan Monnier <monnier@iro.umontreal.ca>2021-01-05 12:28:37 -0500
commit9973019764250ac1f4d77a6b426cdd9c241151c5 (patch)
tree13483c7315e03db43b65a661a206f09903b6c990 /lisp/emacs-lisp/package.el
parent1433a1201447f6f8b610f4d7f78a4b8a739c6572 (diff)
downloademacs-9973019764250ac1f4d77a6b426cdd9c241151c5.tar.gz
emacs-9973019764250ac1f4d77a6b426cdd9c241151c5.tar.bz2
emacs-9973019764250ac1f4d77a6b426cdd9c241151c5.zip
* lisp/emacs-lisp/package.el: Load package-quickstart without package.el
Speed up startup when `package-quickstart` is in use by making it possible to load the quickstart file without having to load `package.el` at all. (package-user-dir, package-directory-list, package-quickstart-file): Preload those variables. (package--get-activatable-pkg): New fun, extracted from `package-activate`. (package-activate): Use it. (package--activate-all): New function, extracted from `package-activate-all`. (package-activate-all): Use it and make the function preloaded. (package--archives-initialize): New function. (package-install): Use it. (list-packages): Avoid `switch-to-buffer`. (package-get-descriptor): New function. * lisp/startup.el (command-line): Simplify the code now that package-user-dir and package-directory-list are preloaded. * lisp/emacs-lisp/autoload.el (make-autoload): Add support for `:initialize #'custom-initialize-delay` in `defcustom`.
Diffstat (limited to 'lisp/emacs-lisp/package.el')
-rw-r--r--lisp/emacs-lisp/package.el90
1 files changed, 60 insertions, 30 deletions
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 40ba1355513..a38363df23e 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -173,12 +173,12 @@ with \"-q\").
Even if the value is nil, you can type \\[package-initialize] to
make installed packages available at any time, or you can
-call (package-initialize) in your init-file."
+call (package-activate-all) in your init-file."
:type 'boolean
:version "24.1")
(defcustom package-load-list '(all)
- "List of packages for `package-initialize' to make available.
+ "List of packages for `package-activate-all' to make available.
Each element in this list should be a list (NAME VERSION), or the
symbol `all'. The symbol `all' says to make available the latest
installed versions of all packages not specified by other
@@ -292,15 +292,18 @@ the package will be unavailable."
:risky t
:version "24.4")
+;;;###autoload
(defcustom package-user-dir (locate-user-emacs-file "elpa")
"Directory containing the user's Emacs Lisp packages.
The directory name should be absolute.
Apart from this directory, Emacs also looks for system-wide
packages in `package-directory-list'."
:type 'directory
+ :initialize #'custom-initialize-delay
:risky t
:version "24.1")
+;;;###autoload
(defcustom package-directory-list
;; Defaults are subdirs named "elpa" in the site-lisp dirs.
(let (result)
@@ -315,6 +318,7 @@ Each directory name should be absolute.
These directories contain packages intended for system-wide; in
contrast, `package-user-dir' contains packages for personal use."
:type '(repeat directory)
+ :initialize #'custom-initialize-delay
:risky t
:version "24.1")
@@ -587,9 +591,8 @@ package."
;;; Installed packages
;; The following variables store information about packages present in
;; the system. The most important of these is `package-alist'. The
-;; command `package-initialize' is also closely related to this
-;; section, but it is left for a later section because it also affects
-;; other stuff.
+;; command `package-activate-all' is also closely related to this
+;; section.
(defvar package--builtins nil
"Alist of built-in packages.
@@ -608,7 +611,7 @@ name (a symbol) and DESCS is a non-empty list of `package-desc'
structures, sorted by decreasing versions.
This variable is set automatically by `package-load-descriptor',
-called via `package-initialize'. To change which packages are
+called via `package-activate-all'. To change which packages are
loaded and/or activated, customize `package-load-list'.")
(put 'package-alist 'risky-local-variable t)
@@ -869,6 +872,20 @@ DIR, sorted by most recently loaded last."
(lambda (x y) (< (cdr x) (cdr y))))))))
;;;; `package-activate'
+
+(defun package--get-activatable-pkg (pkg-name)
+ ;; Is "activatable" a word?
+ (let ((pkg-descs (cdr (assq pkg-name package-alist))))
+ ;; Check if PACKAGE is available in `package-alist'.
+ (while
+ (when pkg-descs
+ (let ((available-version (package-desc-version (car pkg-descs))))
+ (or (package-disabled-p pkg-name available-version)
+ ;; Prefer a builtin package.
+ (package-built-in-p pkg-name available-version))))
+ (setq pkg-descs (cdr pkg-descs)))
+ (car pkg-descs)))
+
;; This function activates a newer version of a package if an older
;; one was already activated. It also loads a features of this
;; package which were already loaded.
@@ -876,24 +893,16 @@ DIR, sorted by most recently loaded last."
"Activate the package named PACKAGE.
If FORCE is true, (re-)activate it if it's already activated.
Newer versions are always activated, regardless of FORCE."
- (let ((pkg-descs (cdr (assq package package-alist))))
- ;; Check if PACKAGE is available in `package-alist'.
- (while
- (when pkg-descs
- (let ((available-version (package-desc-version (car pkg-descs))))
- (or (package-disabled-p package available-version)
- ;; Prefer a builtin package.
- (package-built-in-p package available-version))))
- (setq pkg-descs (cdr pkg-descs)))
+ (let ((pkg-desc (package--get-activatable-pkg package)))
(cond
;; If no such package is found, maybe it's built-in.
- ((null pkg-descs)
+ ((null pkg-desc)
(package-built-in-p package))
;; If the package is already activated, just return t.
((and (memq package package-activated-list) (not force))
t)
;; Otherwise, proceed with activation.
- (t (package-activate-1 (car pkg-descs) nil 'deps)))))
+ (t (package-activate-1 pkg-desc nil 'deps)))))
;;; Installation -- Local operations
@@ -1616,9 +1625,8 @@ that code in the early init-file."
;; `package--initialized' is t.
(package--build-compatibility-table))
-(defvar package-quickstart-file)
-
;;;###autoload
+(progn ;; Make the function usable without loading `package.el'.
(defun package-activate-all ()
"Activate all installed packages.
The variable `package-load-list' controls which packages to load."
@@ -1633,12 +1641,16 @@ The variable `package-load-list' controls which packages to load."
;; save this file so it doesn't need any decoding).
(let ((load-source-file-function nil))
(load qs nil 'nomessage))
- (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))))))))
+ (require 'package)
+ (package--activate-all)))))
+
+(defun package--activate-all ()
+ (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))))))
;;;; Populating `package-archive-contents' from archives
;; This subsection populates the variables listed above from the
@@ -2066,6 +2078,13 @@ PACKAGES are satisfied, i.e. that PACKAGES is computed
using `package-compute-transaction'."
(mapc #'package-install-from-archive packages))
+(defun package--archives-initialize ()
+ "Make sure the list of installed and remote packages are initialized."
+ (unless package--initialized
+ (package-initialize t))
+ (unless package-archive-contents
+ (package-refresh-contents)))
+
;;;###autoload
(defun package-install (pkg &optional dont-select)
"Install the package PKG.
@@ -2086,10 +2105,7 @@ to install it but still mark it as selected."
(progn
;; Initialize the package system to get the list of package
;; symbols for completion.
- (unless package--initialized
- (package-initialize t))
- (unless package-archive-contents
- (package-refresh-contents))
+ (package--archives-initialize)
(list (intern (completing-read
"Install package: "
(delq nil
@@ -2099,6 +2115,7 @@ to install it but still mark it as selected."
package-archive-contents))
nil t))
nil)))
+ (package--archives-initialize)
(add-hook 'post-command-hook #'package-menu--post-refresh)
(let ((name (if (package-desc-p pkg)
(package-desc-name pkg)
@@ -3714,7 +3731,7 @@ short description."
(package-menu--generate nil t)))
;; The package menu buffer has keybindings. If the user types
;; `M-x list-packages', that suggests it should become current.
- (switch-to-buffer buf)))
+ (pop-to-buffer-same-window buf)))
;;;###autoload
(defalias 'package-list-packages 'list-packages)
@@ -4042,10 +4059,12 @@ activations need to be changed, such as when `package-load-list' is modified."
:type 'boolean
:version "27.1")
+;;;###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
+ :initialize #'custom-initialize-delay
:version "27.1")
(defun package--quickstart-maybe-refresh ()
@@ -4111,6 +4130,8 @@ activations need to be changed, such as when `package-load-list' is modified."
;; no-update-autoloads: t
;; End:
"))
+ ;; FIXME: Do it asynchronously in an Emacs subprocess, and
+ ;; don't show the byte-compiler warnings.
(byte-compile-file package-quickstart-file)))
(defun package--imenu-prev-index-position-function ()
@@ -4131,6 +4152,15 @@ beginning of the line."
(package-version-join (package-desc-version package-desc))
(package-desc-summary package-desc))))
+;;;; Introspection
+
+(defun package-get-descriptor (pkg-name)
+ "Return the `package-desc' of PKG-NAME."
+ (unless package--initialized (package-initialize 'no-activate))
+ (or (package--get-activatable-pkg pkg-name)
+ (cadr (assq pkg-name package-alist))
+ (cadr (assq pkg-name package-archive-contents))))
+
(provide 'package)
;;; package.el ends here