Remove the :defer-install keyword

This may reappear as its own add-on to use-package in the future. See https://github.com/jwiegley/use-package/issues/442.
This commit is contained in:
John Wiegley 2017-12-01 11:42:40 -08:00
parent 09be976c18
commit af3b34b022
3 changed files with 52 additions and 235 deletions

View file

@ -15,6 +15,9 @@
- Emacs 24.3 or higher is now a requirement. - Emacs 24.3 or higher is now a requirement.
- The `:defer-install` keyword has been remove. It may reappear as an add-on
module for use-package in a future release. See issue #442 for more details.
### Other changes ### Other changes
- Upgrade license to GPL 3. - Upgrade license to GPL 3.

View file

@ -88,11 +88,6 @@ The check is performed by looking for the module using `locate-library'."
:type 'boolean :type 'boolean
:group 'use-package) :group 'use-package)
(defcustom use-package-always-defer-install nil
"If non-nil, assume `:defer-install t` unless `:defer-install nil` is given."
:type 'boolean
:group 'use-package)
(defcustom use-package-always-ensure nil (defcustom use-package-always-ensure nil
"Treat every package as though it had specified `:ensure SEXP`." "Treat every package as though it had specified `:ensure SEXP`."
:type 'sexp :type 'sexp
@ -140,7 +135,6 @@ the user specified."
(defcustom use-package-keywords (defcustom use-package-keywords
'(:disabled '(:disabled
:pin :pin
:defer-install
:ensure :ensure
:if :if
:when :when
@ -200,9 +194,8 @@ Must be set before loading use-package."
"Function that ensures a package is installed. "Function that ensures a package is installed.
This function is called with four arguments: the name of the This function is called with four arguments: the name of the
package declared in the `use-package' form; the argument passed package declared in the `use-package' form; the argument passed
to `:ensure'; the current `state' plist created by previous to `:ensure'; and the current `state' plist created by previous
handlers; and a keyword indicating the context in which the handlers.
installation is occurring.
Note that this function is called whenever `:ensure' is provided, Note that this function is called whenever `:ensure' is provided,
even if it is nil. It is up to the function to decide on the even if it is nil. It is up to the function to decide on the
@ -210,50 +203,14 @@ semantics of the various values for `:ensure'.
This function should return non-nil if the package is installed. This function should return non-nil if the package is installed.
The default value uses package.el to install the package. The default value uses package.el to install the package."
Possible values for the context keyword are:
:byte-compile - package installed during byte-compilation
:ensure - package installed normally by :ensure
:autoload - deferred installation triggered by an autoloaded
function
:after - deferred installation triggered by the loading of a
feature listed in the :after declaration
:config - deferred installation was specified at the same time
as :demand, so the installation was triggered
immediately
:unknown - context not provided
Note that third-party code can provide other values for the
context keyword by calling `use-package-install-deferred-package'
with the appropriate value."
:type '(choice (const :tag "package.el" use-package-ensure-elpa) :type '(choice (const :tag "package.el" use-package-ensure-elpa)
(function :tag "Custom")) (function :tag "Custom"))
:group 'use-package) :group 'use-package)
(defcustom use-package-pre-ensure-function 'ignore
"Function that is called upon installation deferral.
It is called immediately with the first three arguments that
would be passed to `use-package-ensure-function' (the context
keyword is omitted), but only if installation has been deferred.
It is intended for package managers other than package.el which
might want to activate the autoloads of a package immediately, if
it's installed, but otherwise defer installation until later (if
`:defer-install' is specified). The reason it is set to `ignore'
by default is that package.el activates the autoloads for all
known packages at initialization time, rather than one by one
when the packages are actually requested."
:type '(choice (const :tag "None" ignore)
(function :tag "Custom"))
:group 'use-package)
(defcustom use-package-defaults (defcustom use-package-defaults
'((:config '(t) t) '((:config '(t) t)
(:ensure use-package-always-ensure use-package-always-ensure) (:ensure use-package-always-ensure use-package-always-ensure)
(:defer-install
use-package-always-defer-install
use-package-always-defer-install)
(:pin use-package-always-pin use-package-always-pin)) (:pin use-package-always-pin use-package-always-pin))
"Alist of default values for `use-package' keywords. "Alist of default values for `use-package' keywords.
Each entry in the alist is a list of three elements. The first Each entry in the alist is a list of three elements. The first
@ -639,80 +596,6 @@ manually updated package."
(push pin-form body)) ; or else wait until runtime. (push pin-form body)) ; or else wait until runtime.
body)) body))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; :defer-install
;;
(defvar use-package--deferred-packages (make-hash-table)
"Hash mapping packages to data about their installation.
The keys are not actually symbols naming packages, but rather
symbols naming the features which are the names of \"packages\"
required by `use-package' forms. Since
`use-package-ensure-function' could be set to anything, it is
actually impossible for `use-package' to determine what package
is supposed to provide the feature being ensured just based on
the value of `:ensure'.
Each value is a cons, with the car being the the value passed to
`:ensure' and the cdr being the `state' plist. See
`use-package-install-deferred-package' for information about how
these values are used to call `use-package-ensure-function'.")
(defun use-package-install-deferred-package (name &optional context)
"Install a package whose installation has been deferred.
NAME should be a symbol naming a package (actually, a feature).
This is done by calling `use-package-ensure-function' is called
with four arguments: the key (NAME) and the two elements of the
cons in `use-package--deferred-packages' (the value passed to
`:ensure', and the `state' plist), and a keyword providing
information about the context in which the installation is
happening. (This defaults to `:unknown' but can be overridden by
providing CONTEXT.)
Return t if the package is installed, nil otherwise. (This is
determined by the return value of `use-package-ensure-function'.)
If the package is installed, its entry is removed from
`use-package--deferred-packages'. If the package has no entry in
`use-package--deferred-packages', do nothing and return t."
(interactive
(let ((packages nil))
(maphash (lambda (package info)
(push package packages))
use-package--deferred-packages)
(if packages
(list
(intern
(completing-read "Select package: "
packages nil 'require-match))
:interactive)
(user-error "No packages with deferred installation"))))
(let ((spec (gethash name use-package--deferred-packages)))
(if spec
(when (funcall use-package-ensure-function
name (car spec) (cdr spec)
(or context :unknown))
(remhash name use-package--deferred-packages)
t)
t)))
(defalias 'use-package-normalize/:defer-install 'use-package-normalize-test)
(defun use-package-handler/:defer-install (name keyword defer rest state)
(use-package-process-keywords name rest
;; Just specifying `:defer-install' does not do anything; this
;; sets up a marker so that if `:ensure' is specified as well then
;; it knows to set up deferred installation. But then later, when
;; `:config' is processed, it might turn out that `:demand' was
;; specified as well, and the deferred installation needs to be
;; run immediately. For this we need to know if the deferred
;; installation was actually set up or not, so we need to set one
;; marker value in `:defer-install', and then change it to a
;; different value in `:ensure', if the first one is present. (The
;; first marker is `:defer-install', and the second is `:ensure'.)
(plist-put state :defer-install (when defer :defer-install))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;;; :ensure ;;; :ensure
@ -729,15 +612,13 @@ If the package is installed, its entry is removed from
(concat ":ensure wants an optional package name " (concat ":ensure wants an optional package name "
"(an unquoted symbol name)"))))))) "(an unquoted symbol name)")))))))
(defun use-package-ensure-elpa (name ensure state context &optional no-refresh) (defun use-package-ensure-elpa (name ensure state &optional no-refresh)
(let ((package (or (and (eq ensure t) (use-package-as-symbol name)) (let ((package
(or (and (eq ensure t) (use-package-as-symbol name))
ensure))) ensure)))
(when package (when package
(require 'package) (require 'package)
(or (package-installed-p package) (unless (package-installed-p package)
;; Contexts in which the confirmation prompt is bypassed.
(not (or (member context '(:byte-compile :ensure :config))
(y-or-n-p (format "Install package %S?" package))))
(condition-case-unless-debug err (condition-case-unless-debug err
(progn (progn
(when (assoc package (bound-and-true-p (when (assoc package (bound-and-true-p
@ -759,36 +640,17 @@ If the package is installed, its entry is removed from
:error)))))))) :error))))))))
(defun use-package-handler/:ensure (name keyword ensure rest state) (defun use-package-handler/:ensure (name keyword ensure rest state)
(let* ((body (use-package-process-keywords name rest (let* ((body (use-package-process-keywords name rest state)))
;; Here we are conditionally updating the marker ;; We want to avoid installing packages when the `use-package' macro is
;; value for deferred installation; this will be ;; being macro-expanded by elisp completion (see `lisp--local-variables'),
;; checked later by `:config'. For more information ;; but still install packages when byte-compiling, to avoid requiring
;; see `use-package-handler/:defer-install'. ;; `package' at runtime.
(if (eq (plist-get state :defer-install) (if (bound-and-true-p byte-compile-current-file)
:defer-install)
(plist-put state :defer-install :ensure)
state))))
;; We want to avoid installing packages when the `use-package'
;; macro is being macro-expanded by elisp completion (see
;; `lisp--local-variables'), but still do install packages when
;; byte-compiling to avoid requiring `package' at runtime.
(cond
((plist-get state :defer-install)
(push
`(puthash ',name '(,ensure . ,state)
use-package--deferred-packages)
body)
(push `(,use-package-pre-ensure-function
',name ',ensure ',state)
body))
((bound-and-true-p byte-compile-current-file)
;; Eval when byte-compiling, ;; Eval when byte-compiling,
(funcall use-package-ensure-function (funcall use-package-ensure-function name ensure state)
name ensure state :byte-compile))
;; or else wait until runtime. ;; or else wait until runtime.
(t (push `(,use-package-ensure-function (push `(,use-package-ensure-function ',name ',ensure ',state)
',name ',ensure ',state :ensure) body))
body)))
body)) body))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1272,35 +1134,6 @@ representing symbols (that may need to be autloaded)."
(defalias 'use-package-normalize/:defer 'use-package-normalize-predicate) (defalias 'use-package-normalize/:defer 'use-package-normalize-predicate)
(defun use-package--autoload-with-deferred-install
(command package-name)
"Return a form defining an autoload supporting deferred install."
`(let* ((load-list-item '(defun . ,command))
(already-loaded (member load-list-item current-load-list)))
(defun ,command (&rest args)
"[Arg list not available until function definition is loaded.]
\(fn ...)"
(interactive)
(if (bound-and-true-p use-package--recursive-autoload)
(use-package-error
(format "Autoloading failed to define function %S"
',command))
(when (use-package-install-deferred-package
',package-name :autoload)
(require ',package-name)
(let ((use-package--recursive-autoload t))
(if (called-interactively-p 'any)
(call-interactively ',command)
(apply ',command args))))))
;; This prevents the user's init-file from being recorded as the
;; definition location for the function before it is actually
;; loaded. (Our goal is to leave the `current-load-list'
;; unchanged, so we only remove the entry for this function if it
;; was not already present.)
(unless already-loaded
(setq current-load-list (remove load-list-item current-load-list)))))
(defun use-package-handler/:defer (name keyword arg rest state) (defun use-package-handler/:defer (name keyword arg rest state)
(let ((body (use-package-process-keywords name rest (let ((body (use-package-process-keywords name rest
(plist-put state :deferred t))) (plist-put state :deferred t)))
@ -1318,13 +1151,7 @@ representing symbols (that may need to be autloaded)."
(when (symbolp command) (when (symbolp command)
(append (append
`((unless (fboundp ',command) `((unless (fboundp ',command)
;; Here we are checking the marker value set in (autoload #',command ,name-string nil t)))
;; `use-package-handler/:ensure' to see if deferred
;; installation is actually happening. See
;; `use-package-handler/:defer-install' for more information.
,(if (eq (plist-get state :defer-install) :ensure)
(use-package--autoload-with-deferred-install command name)
`(autoload #',command ,name-string nil t))))
(when (bound-and-true-p byte-compile-current-file) (when (bound-and-true-p byte-compile-current-file)
`((eval-when-compile `((eval-when-compile
(declare-function ,command ,name-string))))))) (declare-function ,command ,name-string)))))))
@ -1374,15 +1201,10 @@ representing symbols (that may need to be autloaded)."
(setq arg (cons :all arg))) (setq arg (cons :all arg)))
(use-package-concat (use-package-concat
(when arg (when arg
(list (funcall (use-package-require-after-load arg) (list (funcall
(use-package-require-after-load arg)
(macroexp-progn (macroexp-progn
;; Here we are checking the marker value for deferred `((require (quote ,name) nil t))))))
;; installation set in `use-package-handler/:ensure'.
;; See also `use-package-handler/:defer-install'.
`(,@(when (eq (plist-get state :defer-install) :ensure)
`((use-package-install-deferred-package
'name :after)))
(require (quote ,name) nil t))))))
body))) body)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1441,12 +1263,6 @@ representing symbols (that may need to be autloaded)."
`((eval-after-load ,(if (symbolp name) `',name name) `((eval-after-load ,(if (symbolp name) `',name name)
',(macroexp-progn config-body)))) ',(macroexp-progn config-body))))
;; Here we are checking the marker value for deferred installation set
;; in `use-package-handler/:ensure'. See also
;; `use-package-handler/:defer-install'.
(when (eq (plist-get state :defer-install) :ensure)
(use-package-install-deferred-package name :config))
(use-package--with-elapsed-timer (use-package--with-elapsed-timer
(format "Loading package %s" name) (format "Loading package %s" name)
(if use-package-expand-minimally (if use-package-expand-minimally
@ -1709,10 +1525,8 @@ this file. Usage:
`:magic-fallback', or `:interpreter'. This can be an integer, `:magic-fallback', or `:interpreter'. This can be an integer,
to force loading after N seconds of idle time, if the package to force loading after N seconds of idle time, if the package
has not already been loaded. has not already been loaded.
:after Defer loading of a package until after any of the named :after Defer loading of a package until after any of the named
features are loaded. features are loaded.
:demand Prevent deferred loading in all cases. :demand Prevent deferred loading in all cases.
:if EXPR Initialize and load only if EXPR evaluates to a non-nil value. :if EXPR Initialize and load only if EXPR evaluates to a non-nil value.

View file

@ -194,28 +194,28 @@
(match-expansion (match-expansion
(use-package foo :ensure t) (use-package foo :ensure t)
`(progn `(progn
(use-package-ensure-elpa 'foo 't 'nil :ensure) (use-package-ensure-elpa 'foo 't 'nil)
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
(let ((use-package-always-ensure t)) (let ((use-package-always-ensure t))
(match-expansion (match-expansion
(use-package foo :ensure t) (use-package foo :ensure t)
`(progn `(progn
(use-package-ensure-elpa 'foo 't 'nil :ensure) (use-package-ensure-elpa 'foo 't 'nil)
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
(let ((use-package-always-ensure nil)) (let ((use-package-always-ensure nil))
(match-expansion (match-expansion
(use-package foo :ensure nil) (use-package foo :ensure nil)
`(progn `(progn
(use-package-ensure-elpa 'foo 'nil 'nil :ensure) (use-package-ensure-elpa 'foo 'nil 'nil)
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
(let ((use-package-always-ensure t)) (let ((use-package-always-ensure t))
(match-expansion (match-expansion
(use-package foo :ensure nil) (use-package foo :ensure nil)
`(progn `(progn
(use-package-ensure-elpa 'foo 'nil 'nil :ensure) (use-package-ensure-elpa 'foo 'nil 'nil)
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
(let ((use-package-always-ensure nil)) (let ((use-package-always-ensure nil))
@ -230,7 +230,7 @@
(match-expansion (match-expansion
(use-package foo :load-path "foo") (use-package foo :load-path "foo")
`(progn `(progn
(use-package-ensure-elpa 'foo 'nil 'nil :ensure) (use-package-ensure-elpa 'foo 'nil 'nil)
(eval-and-compile (eval-and-compile
(add-to-list 'load-path ,(pred stringp))) (add-to-list 'load-path ,(pred stringp)))
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
@ -239,7 +239,7 @@
(match-expansion (match-expansion
(use-package foo :ensure nil :load-path "foo") (use-package foo :ensure nil :load-path "foo")
`(progn `(progn
(use-package-ensure-elpa 'foo 'nil 'nil :ensure) (use-package-ensure-elpa 'foo 'nil 'nil)
(eval-and-compile (eval-and-compile
(add-to-list 'load-path ,(pred stringp))) (add-to-list 'load-path ,(pred stringp)))
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
@ -248,7 +248,7 @@
(match-expansion (match-expansion
(use-package foo :ensure nil :load-path "foo") (use-package foo :ensure nil :load-path "foo")
`(progn `(progn
(use-package-ensure-elpa 'foo 'nil 'nil :ensure) (use-package-ensure-elpa 'foo 'nil 'nil)
(eval-and-compile (eval-and-compile
(add-to-list 'load-path ,(pred stringp))) (add-to-list 'load-path ,(pred stringp)))
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
@ -257,7 +257,7 @@
(match-expansion (match-expansion
(use-package foo :ensure t :load-path "foo") (use-package foo :ensure t :load-path "foo")
`(progn `(progn
(use-package-ensure-elpa 'foo 't 'nil :ensure) (use-package-ensure-elpa 'foo 't 'nil)
(eval-and-compile (eval-and-compile
(add-to-list 'load-path ,(pred stringp))) (add-to-list 'load-path ,(pred stringp)))
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
@ -266,14 +266,14 @@
(match-expansion (match-expansion
(use-package foo :ensure t :load-path "foo") (use-package foo :ensure t :load-path "foo")
`(progn `(progn
(use-package-ensure-elpa 'foo 't 'nil :ensure) (use-package-ensure-elpa 'foo 't 'nil)
(eval-and-compile (eval-and-compile
(add-to-list 'load-path ,(pred stringp))) (add-to-list 'load-path ,(pred stringp)))
(require 'foo nil 'nil)))) (require 'foo nil 'nil))))
(let (tried-to-install) (let (tried-to-install)
(flet ((use-package-ensure-elpa (flet ((use-package-ensure-elpa
(name ensure state context &optional no-refresh) (name ensure state &optional no-refresh)
(when ensure (when ensure
(setq tried-to-install name))) (setq tried-to-install name)))
(require (&rest ignore))) (require (&rest ignore)))