Subject: bug#77188: 31.0.50; describe-package: Duplicate installed versions and incorrect Install button state

From: Philip Kaludercic <[email-masked]>
Date: Fri, 11 Apr 2025 15:06:00 +0000

david <[email-masked]> writes:

> Hi Emacs developers,
>
> I found a bug in the `describe-package` interface.  Here are the steps
> to reproduce it:
>
> 1. Open Emacs and run `M-x list-packages RET`.
> 2. Click on a package that is already installed (Status: Installed).
> 3. In the "Other versions" section, click on the same version that is
>    already installed.
> 4. The package description now shows "Install" even though the package
>    is already installed.
> 5. If you click "Install", the package is reinstalled, and the "Other
>    versions" section shows the same version twice as installed.
>
> The same behavior occurs for packages with Status: dependency.  The
> difference is that when you click "Install" in `describe-package`, the
> package changes its status in `list-packages` from "dependency" to
> "installed".  Additionally, the package appears duplicated in the "Other
> versions" section.  However, after restarting Emacs, the package returns
> to its original "dependency" status in `list-packages`.
>
> Expected behavior:
> - The "Install" button should not be shown if the package is already
>   installed.  Alternatively, the button could be renamed to "Reinstall"
>   or replaced with a "Delete" button to better reflect the available
>   actions for an already installed package.
> - The "Other versions" section should not display duplicate entries for
>   the same installed version.  If you click "Install" again, the package
>   is overwritten, and a third duplicate entry appears as installed.

I believe the following patch should address these issues:

diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 83bc36a4596..c3f3b9c9803 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -2890,8 +2891,9 @@ describe-package-1
            (insert " from " (format "%s" archive))
            (insert " -- ")
            (package-make-button
-            "Install"
-            'action 'package-install-button-action
+            (if (package-installed-p (package-desc-name pkg))
+                "Reinstall" "Install")
+            'action #'package-install-button-action
             'package-desc desc))
           (t (insert (capitalize status) ".")))
     (insert "\n")
@@ -2983,7 +2985,7 @@ describe-package-1
                              (cdr (assq name package-archive-contents))
                              (let ((bi (assq name package--builtins)))
                                (if bi (list (package--from-builtin bi))))))
-           (other-pkgs (delete desc all-pkgs)))
+           (other-pkgs (delete-dups (delete desc all-pkgs))))
       (when other-pkgs
         (package--print-help-section "Other versions"
           (mapconcat (lambda (opkg)

> In GNU Emacs 31.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version
>  3.24.43, cairo version 1.18.2) of 2025-03-16 built on fedora
> Repository revision: eab14d68b2e72b9a6b8b0cc67c9667c2bfbed4f5
> Repository branch: master
> System Description: Fedora Linux 41 (Workstation Edition)
>
> Configured using:
>  'configure --with-imagemagick --with-pgtk --with-tree-sitter
>  --with-mailutils --with-sound=yes --with-pdumper=yes
>  --with-dumping=pdumper --with-file-notification=yes --with-gnutls'
>
> Configured features:
> ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ
> IMAGEMAGICK JPEG LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 MODULES
> NATIVE_COMP NOTIFY INOTIFY PDUMPER PGTK PNG RSVG SECCOMP SOUND SQLITE3
> THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER WEBP XIM GTK3 ZLIB
>
> Important settings:
>   value of $LANG: en_US.UTF-8
>   value of $XMODIFIERS: @im=ibus
>   locale-coding-system: utf-8-unix
>
> Major mode: Lisp Interaction
>
> Minor modes in effect:
>   tooltip-mode: t
>   global-eldoc-mode: t
>   eldoc-mode: t
>   show-paren-mode: t
>   electric-indent-mode: t
>   mouse-wheel-mode: t
>   tool-bar-mode: t
>   menu-bar-mode: t
>   file-name-shadow-mode: t
>   global-font-lock-mode: t
>   font-lock-mode: t
>   blink-cursor-mode: t
>   minibuffer-regexp-mode: t
>   line-number-mode: t
>   indent-tabs-mode: t
>   transient-mark-mode: t
>   auto-composition-mode: t
>   auto-encryption-mode: t
>   auto-compression-mode: t
>
> Load-path shadows:
> None found.
>
> Features:
> (shadow sort mail-extr ert ewoc debug backtrace org ob ob-tangle ob-ref
> ob-lob ob-table ob-exp org-macro org-src sh-script smie treesit
> executable ob-comint org-pcomplete pcomplete org-list org-footnote
> org-faces org-entities noutline outline ob-emacs-lisp ob-core ob-eval
> org-cycle org-table ol org-fold org-fold-core org-keys oc org-loaddefs
> find-func cal-menu calendar cal-loaddefs org-version org-compat org-macs
> format-spec debbugs-gnu pcase add-log debbugs soap-client warnings
> rng-xsd rng-dt rng-util xsd-regexp xml debbugs-compat bug-reference
> thingatpt info debbugs-autoloads easy-mmode loaddefs-gen radix-tree
> tar-mode arc-mode archive-mode cl-extra help-mode misearch multi-isearch
> mm-archive mule-util cus-edit pp cus-start cus-load wid-edit gnutls
> network-stream url-cache url-http url-auth url-gw nsm
> display-line-numbers finder-inf package browse-url xdg url url-proxy
> url-privacy url-expand url-methods url-history url-cookie
> generate-lisp-file url-domsuf url-util url-handlers url-parse
> auth-source cl-seq eieio eieio-core cl-macs icons json map byte-opt gv
> url-vars emacsbug lisp-mnt message mailcap yank-media puny dired
> dired-loaddefs rfc822 mml mml-sec password-cache epa derived epg rfc6068
> epg-config gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231
> mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums
> mm-util mail-prsvr mail-utils compile text-property-search comint
> ansi-osc ansi-color ring comp-run bytecomp byte-compile comp-common rx
> time-date subr-x cl-loaddefs cl-lib rmc iso-transl tooltip cconv eldoc
> paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode
> mwheel term/pgtk-win pgtk-win term/common-win touch-screen pgtk-dnd
> tool-bar dnd fontset image regexp-opt fringe tabulated-list replace
> newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar
> rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock
> font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq
> simple cl-generic indonesian philippine cham georgian utf-8-lang
> misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
> cp51932 hebrew greek romanian slovak czech european ethiopic indian
> cyrillic chinese composite emoji-zwj charscript charprop case-table
> epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button
> loaddefs theme-loaddefs faces cus-face macroexp files window
> text-properties overlay sha1 md5 base64 format env code-pages mule
> custom widget keymap hashtable-print-readable backquote threads dbusbind
> inotify dynamic-setting system-font-setting font-render-setting cairo
> gtk pgtk multi-tty move-toolbar make-network-process tty-child-frames
> native-compile emacs)
>
> Memory information:
> ((conses 16 422845 65583) (symbols 48 20294 0) (strings 32 88877 8835)
>  (string-bytes 1 2486247) (vectors 16 35552)
>  (vector-slots 8 422683 21928) (floats 8 128 150)
>  (intervals 56 25436 217) (buffers 992 17))