Subject: Re: bug#62720: 29.0.60; Not easy at all to upgrade :core packages like Eglot

From: Philip Kaludercic <[email-masked]>
Date: Wed, 12 Apr 2023 19:39:20 +0000

Eli Zaretskii <[email-masked]> writes:

>> From: João Távora <[email-masked]>
>> Date: Wed, 12 Apr 2023 18:14:28 +0100
>> Cc: "Philip K." <[email-masked]>, Stefan Monnier
>> <[email-masked]>, [email-masked],
>> 	Lars Ingebrigtsen <[email-masked]>
>> 
>> Please, in normal non-shouting case, explain to me how you think
>> that the behavior of an existing
>> command can be changed with "completely separate code". 
>
> I already did: either (1) add a prefix argument to an existing
> command, which will then trigger the new behavior, or (2) add a
> separate command.

Here you have (1):

>From 09a9e769ed0c7024c33bc135c57894daff8764af Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <[email-masked]>
Date: Wed, 12 Apr 2023 14:26:39 +0200
Subject: [PATCH] Allow upgrading built-in packages

* lisp/emacs-lisp/package.el (package--upgradable-built-in-p): Add new
utility predicate.
(package-compute-transaction): Check if an installed package is
built-in while resolving dependencies and allow it to be installed.
(package-install): Suggest upgrading built-in packages in the
interactive specification, when invoked with a prefix argument.  Allow
upgrading built-in packages
---
 lisp/emacs-lisp/package.el | 41 +++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index f92afe56b76..03e63ee7227 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -797,6 +797,20 @@ package-built-in-p
         (require 'finder-inf nil t) ; For `package--builtins'.
         (assq package package--builtins))))))
 
+(defun package--upgradable-built-in-p (package)
+  "Check if a built-in PACKAGE can be upgraded.
+This command differs from `package-built-in-p' in that it only
+returns a non-nil value if the user has not installed a more
+recent version of the package from a package archive."
+  (and (not (assq (cond
+                   ((package-desc-p package)
+                    (package-desc-name package))
+                   ((stringp package) (intern package))
+                   ((symbolp package) package)
+                   ((error "Unknown package format: %S" package)))
+                  (package--alist)))
+       (package-built-in-p package)))
+
 (defun package--autoloads-file-name (pkg-desc)
   "Return the absolute name of the autoloads file, sans extension.
 PKG-DESC is a `package-desc' object."
@@ -1908,7 +1922,16 @@ package-compute-transaction
                  (package-version-join (package-desc-version already)))))
       (cond
        (already nil)
-       ((package-installed-p next-pkg next-version) nil)
+       ;; If a package is installed, we don't need to continue.
+       ;; Built-in packages constitute an exception, because we want
+       ;; to allow the user to "upgrade" from a built-in version to a
+       ;; potentially newer version available on ELPA (bug#62720).
+       ((and (not (package--upgradable-built-in-p next-pkg))
+             (package-installed-p next-pkg next-version)))
+       ;; The pseudo-package Emacs is always installed and built-in.
+       ;; It cannot be upgraded, so we make sure not to proceed beyond
+       ;; this point when resolving dependencies.
+       ((eq next-pkg 'emacs))
 
        (t
         ;; A package is required, but not installed.  It might also be
@@ -2187,7 +2210,9 @@ package-install
   "Install the package PKG.
 PKG can be a `package-desc' or a symbol naming one of the
 available packages in an archive in `package-archives'.  When
-called interactively, prompt for the package name.
+called interactively, prompt for the package name.  When invoked
+with a prefix argument, the prompt will include built-in packages
+that can be upgraded via an archive.
 
 Mark the installed package as selected by adding it to
 `package-selected-packages'.
@@ -2205,11 +2230,13 @@ package-install
      (package--archives-initialize)
      (list (intern (completing-read
                     "Install package: "
-                    (delq nil
-                          (mapcar (lambda (elt)
-                                    (unless (package-installed-p (car elt))
-                                      (symbol-name (car elt))))
-                                  package-archive-contents))
+                    (mapcan
+                     (lambda (elt)
+                       (and (or (and current-prefix-arg
+                                     (package--upgradable-built-in-p (car elt)))
+                                (not (package-installed-p (car elt))))
+                            (list (car elt))))
+                     package-archive-contents)
                     nil t))
            nil)))
   (package--archives-initialize)
-- 
2.39.2