Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for deferred installation #433

Merged
merged 9 commits into from
Mar 19, 2017
Merged

Conversation

raxod502
Copy link
Collaborator

@raxod502 raxod502 commented Mar 9, 2017

First cut at :defer-install keyword

This new keyword, if provided along with a non-nil value, causes the action
of :ensure to be deferred until "necessary". Package installation can be
triggered by the user calling the new interactive function
`use-package-install-deferred-package', or by the feature declared by the
`use-package' form being required. This latter behavior seems to be the
simplest way to make sure that package installation actually takes place
when it needs to, but it requires that an advice be added to `require',
which may be considered overly intrusive. (Also, it's generally considered
bad practice for functions in Emacs to put advice on other functions in
Emacs.) Thus it may make sense to add an option or function to explicitly
enable this behavior, if there does not turn out to be a better way to
accomplish deferred installation.

Documentation has not been updated to reflect :defer-install yet.

Considering how to address #409. I think that this is not the right
approach to take (esp. because autoloads are handled in the C code and
therefore do not respect the advice on require), but I thought I
would post my progress so far. I think I have an idea about how to
proceed.

NB: The text of this message is severely obsolete. I completely changed the implementation; in particular, there are no advices placed on require!

Modify the expected API of `use-package-ensure-function' so that it is
passed three arguments: the name of the package declared in the
`use-package' form; the argument passed to `:ensure'; and the current
`state' plist created by previous handlers. (Previously, it was only
given a single argument, which was the argument passed to `:ensure',
or the name of the package declared in the `use-package' form, if the
former was `t'.

This allows for more flexibility in the capabilities of the
`use-package-ensure-function' implementation. For example, its
behavior can change depending on the values of other keywords, if
those keywords modify the `state' plist appropriately.
This new keyword, if provided along with a non-nil value, causes the
action of :ensure to be deferred until "necessary". Package
installation can be triggered by the user calling the new interactive
function `use-package-install-deferred-package', or by the feature
declared by the `use-package' form being required. This latter
behavior seems to be the simplest way to make sure that package
installation actually takes place when it needs to, but it requires
that an advice be added to `require', which may be considered overly
intrusive. (Also, it's generally considered bad practice for functions
in Emacs to put advice on other functions in Emacs.) Thus it may make
sense to add an option or function to explicitly enable this behavior,
if there does not turn out to be a better way to accomplish deferred
installation.

Documentation has not been updated to reflect :defer-install yet.
Now it properly reflects the API changes recently made.
This time around, I've gotten rid of the advice on `require' (that was
never going to work) and instead made `use-package' try to handle
loading the package at the appropriate time. In particular, when
deferred installation is active, all the autoloads generated by
`use-package' are not regular autoloads, but regular functions that
will install the relevant package, require the relevant feature, and
only then call the newly defined (autoloaded) function.

Some smarter logic has been added to make sure things like `:demand'
play nicely with the autoloading system; see the extensive comment in
`use-package-handler/:defer-install' for more information on how that
works.

There was a section in `use-package-install-deferred-package' which
referred to a nonexistent variable `use-package--deferred-features';
that has been removed.

There is now, in addition to `use-package-ensure-function', a new
variable called `use-package-pre-ensure-function'. This is intended
for use by package managers which, unlike package.el, activate
autoloads package-by-package instead of all at once. Even if a package
is marked for deferred installation, the user would likely want its
autoloads activated immediately *if* it was already installed. The
logic for doing that can now be put in
`use-package-pre-ensure-function'.
* A quoting error has been fixed in `use-package-handler/:defer'.
* `use-package-install-deferred-package' has been updated to return t
  if the package was actually installed, and nil otherwise.
* The fake autoloads generated during deferred installation are
  doctored so Emacs does not think they were defined in the user's
  init-file.
* The docstrings of the fake autoloads have been improved.
* Arguments and interactivity are now correctly passed to the
  autoloaded function.
* The autoload now skips requiring the feature and calling the
  original function if the user declines to install the package. This
  prevents unprofessional errors.
@raxod502
Copy link
Collaborator Author

raxod502 commented Mar 9, 2017

It works! Here is a short demo: https://youtu.be/az5C1nd3fh0. (In case you are wondering about the text that is printed when I install the package, that is from my package manager—but this should work with package.el too.)

Usage looks like this:

(use-package swift-mode
  :defer-install t
  :mode "\\.swift\\'")

In theory, specifying :defer-install t should "just work", in that all entry points to loading the package normally created by use-package will now prompt the user to install the package before requiring the feature.

I'll be testing this in my own config. Comments and suggestions would be appreciated!

@raxod502 raxod502 changed the title [WIP] Support for deferred installation [RFC] Support for deferred installation Mar 9, 2017
@raxod502
Copy link
Collaborator Author

raxod502 commented Mar 11, 2017

I've realized that the confirmation prompt needs to be moved out of the use-package logic and into to the package-manager-specific :ensure function, since otherwise there is no way to only prompt the user if the package is not installed.

I'm currently working on this.

@raxod502
Copy link
Collaborator Author

It appears to be at least mostly working! I have integrated deferred installation with my config, and out of 52 packages only 25 are installed on initial Emacs launch.

@raxod502
Copy link
Collaborator Author

Wow, how did I base this branch on a four-week-old commit? I've fixed the merge conflicts.

@jwiegley jwiegley merged commit bf9a73f into jwiegley:master Mar 19, 2017
@drot
Copy link

drot commented Mar 19, 2017

After this merge the :after keyword stopped working, if I have something like this:

(use-package info+
  :ensure t
  :after info)

info+ doesn't get loaded anymore.

@raxod502
Copy link
Collaborator Author

That's not good—:defer-install should not affect behavior at all unless you explicitly include it in the use-package form. Let me see if I can reproduce the issue.

raxod502 added a commit to raxod502/use-package that referenced this pull request Mar 19, 2017
Commit [1] broke the functionality of :after (see [2]) due to an
extraneous quote being added.

[1]: bf9a73f
[2]: jwiegley#433 (comment)
This was referenced Mar 19, 2017
@raxod502 raxod502 deleted the defer-install branch March 19, 2017 15:40
@raxod502
Copy link
Collaborator Author

@drot Should be fixed now, it was a silly quoting error.

@raxod502
Copy link
Collaborator Author

raxod502 commented Mar 26, 2017 via email

@blaenk
Copy link

blaenk commented Mar 26, 2017

Just found out about this through the commit log and I think it's pretty cool! Thanks for taking the initiative to implement it!

I was wondering if there's a way to have something like use-package-always-ensure, or some way to have behavior as "always assume :ensure t unless :ensure is explicitly present in a use-package form which specifies otherwise (e.g. nil or a package name), and beyond that assume :defer-install t so that the package is only installed if it's needed because e.g. it was required, unless the use-package form explicitly has :defer-install nil or something."

So I guess said another way, assume :defer-install t unless it's overridden in the use-package declaration, and otherwise assume :ensure t in a similar manner (as already covered by use-package-always-ensure).

I was reading through the diff's elisp doc strings but couldn't figure out if this was already possible. If not, is it even possible? Or aside from that, is there a reason why that would be inadvisable?

raxod502 added a commit to raxod502/use-package that referenced this pull request Mar 26, 2017
@raxod502
Copy link
Collaborator Author

@blaenk This is a trivial change so I made a pull request, see #443. One thing to note is that :defer-install t does nothing unless :ensure t is also given (or, of course, use-package-always-ensure is non-nil).

@raxod502 raxod502 changed the title [RFC] Support for deferred installation Support for deferred installation Mar 26, 2017
@TrunovS
Copy link

TrunovS commented Jan 27, 2020

@raxod502 It seems that change removed from master now. Is deferred install now possible in another way?

@raxod502
Copy link
Collaborator Author

No, there's no way to achieve this behavior. If the feature were to be reimplemented, it should be done at the package-manager level, in my opinion. The ideal place would be straight.el, where there is already a mechanism for saving autoloads persistently (sort of) and it would be easy to extend the existing code to generate deferred-installation stubs for all entry points to the package, not just the ones mentioned in use-package: a better solution.

jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 24, 2022
[RFC] Support for deferred installation
GitHub-reference: jwiegley/use-package#433
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 24, 2022
Commit [1] broke the functionality of :after (see [2]) due to an
extraneous quote being added.

[1]: 2b8b608
[2]: jwiegley/use-package#433 (comment)
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 24, 2022
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 29, 2022
[RFC] Support for deferred installation
GitHub-reference: jwiegley/use-package#433
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 29, 2022
Commit [1] broke the functionality of :after (see [2]) due to an
extraneous quote being added.

[1]: bd2afa5
[2]: jwiegley/use-package#433 (comment)
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants