jwiegley / use-package

A use-package declaration for simplifying your .emacs
https://jwiegley.github.io/use-package
GNU General Public License v3.0
4.37k stars 260 forks source link

:pin option ignored when trying to install newer version of builtin packages #955

Open markokocic opened 2 years ago

markokocic commented 2 years ago

I have the following in my config where is gnu defined to point to gnu elpa repository.

(use-package org :pin gnu)

Expected result: org-mode is installed and loaded from the repository specified with :pin.

Actual result: use-package loads builtin version of org that is bundled with Emacs itself.

Solutions: If :pin option is used, use-package should not allow loading specified package from other sources, including builtin packages.

Note: This is related to #319 but not specific to org-mode since it applies to all packages.

manufactory commented 2 years ago

Another scenario is installing project.el from GNU ELPA. project.el

(use-package project
  :pin gnu)

just keeps the built-in project.el.

markokocic commented 1 year ago

Just to reply to myself, I worked around this by having the following in my init file:

(defun mk/ignore-builtin (pkg)
  (assq-delete-all pkg package--builtins)
  (assq-delete-all pkg package--builtin-versions))

(mk/ignore-builtin 'org)
(use-package org ....)

This will ensure that org is removed from the list of Emacs builtins before calling use-package.

Since this is a relatively common problem, it would be good if we had use-package supportin this use case natively, by adding a new option like :ignore-builtin t

skangas commented 1 year ago

Maybe I'm missing something here, but I don't think :pin ever supported upgrading packages? It sounds like you should just use M-x list-packages and upgrade packages in the normal way here, no?

markokocic commented 1 year ago

Regardless which version you installed or upgraded from the M-x list-packages screen. Upon restarting emacs, use-package will ignore :pin and just load builtin version if it exists.

Snippet from https://github.com/jwiegley/use-package/issues/955#issuecomment-1183003690 works around this, but it would be nice if use-package would natively support overriding builtin packages, since people that add use-package snippet in their .emacs file usually expect to load the latest version from elpa, like for any other package, and not from the emacs builtin disribution.

Spauldo commented 1 year ago

I use Emacs on multiple machines and copy my config manually without the elpa directory. Thanks to use-package, my init.el downloads and installs everything I need the first time I start Emacs.

Except for org. I just tested again and even with :pin gnu I get version 9.5.5 (9.6 is in ELPA as of the time of this writing).

As a user, :pin seems like the intuitive way to solve this. :ignore-builtin t feels more like a workaround, but I'd take that if it let me upgrade org with use-package.

Spauldo commented 1 year ago

You know, I didn't think until after I wrote this to check if package--builtins and package--builtin-versions were dynamically scoped (they are). I could have replaced this whole macro with a let statement. This works though and I've got work to do, so I'm leaving this here in case it helps someone else.

I can delete my ~/.emacs.d/elpa directory, start Emacs, and have my full config including the ELPA version of org-mode. I assume this would work with other builtins that are also in ELPA.

(defmacro with-ignored-builtin-package (pkg &rest body)
  "Ignore builtin PKG while executing BODY."
  (declare (indent defun))
  (let ((pb-orig (gensym))
        (pbv-orig (gensym))
    (ret (gensym)))
    `(let ((,pb-orig package--builtins)
           (,pbv-orig package--builtin-versions))
       (unless package--builtins
         (package-initialize))
       (setf package--builtins
             (assoc-delete-all ,pkg package--builtins))
       (setf package--builtin-versions
             (assoc-delete-all ,pkg package--builtin-versions))
       (setf ,ret (progn ,@body))
       (setf package--builtins ,pb-orig)
       (setf package--builtin-versions ,pbv-orig)
       ,ret)))

Then all you have to do to get org-mode is something like this:

(with-ignored-builtin-package 'org
  (use-package org
    :pin gnu
    :ensure t
    :hook (org-mode . jds/org-mode-hook)
    :init
    (setq org-latex-classes nil)
    :custom
    (org-src-fontify-natively t)
    (org-babel-load-languages '((C . t)
                                (emacs-lisp . t)
                                (fortran . t)
                                (lisp . t)
                                (maxima . t)
                                (perl . t)
                                (scheme . t)
                                (shell . t)))))

Remember to put it high in your config file so Emacs doesn't load the built-in org-mode first, otherwise you might get weird stuff like (void-function org-assert-version).