Subject: bug#57503: 28.1.91; package-selected-packages should not be saved to custom-file

From: Robert Pluim <[email-masked]>
Date: Fri, 02 Sep 2022 16:33:52 +0200

>>>>> On Fri, 02 Sep 2022 15:17:55 +0200, Lars Ingebrigtsen <[email-masked]> said:

    Lars> Philip Kaludercic <[email-masked]> writes:
    >> How about writing it into a file like
    >> "~/.config/emacs/elpa/selected-packages"?

    Lars> The defcustom could just be changed to a define-multisession-variable.

For values of 'just' that are a little bigger than changing that one
line 😀

roughʼnʼready patch attached. Seems to work fine. Iʼve not tested the
interaction with a .emacs that has package-selected-packages set, but
if I understand multisession variables correctly that will just be
ignored.

>From 1a84bfbc1b568da6bf63bf9679a317b29f78d0e9 Mon Sep 17 00:00:00 2001
From: Robert Pluim <[email-masked]>
Date: Fri, 2 Sep 2022 16:28:11 +0200
Subject: [PATCH] Make package-selected-packages a multisession variable
To: [email-masked]

---
 lisp/emacs-lisp/package.el | 63 ++++++++++++++++++--------------------
 1 file changed, 30 insertions(+), 33 deletions(-)

diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index ed23ee5f22..cda55bd90e 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -384,7 +384,8 @@ package-unsigned-archives
   :risky t
   :version "24.4")
 
-(defcustom package-selected-packages nil
+(require 'multisession)
+(define-multisession-variable package-selected-packages nil
   "Store here packages installed explicitly by user.
 This variable is fed automatically by Emacs when installing a new package.
 This variable is used by `package-autoremove' to decide
@@ -395,8 +396,8 @@ package-selected-packages
 To check if a package is contained in this list here, use
 `package--user-selected-p', as it may populate the variable with
 a sane initial value."
-  :version "25.1"
-  :type '(repeat symbol))
+  :synchronized t
+  :package "package")
 
 (defcustom package-native-compile nil
   "Non-nil means to natively compile packages as part of their installation.
@@ -1907,22 +1908,15 @@ package--find-non-dependencies
              unless (memq name dep-list)
              collect name)))
 
-(defun package--save-selected-packages (&optional value)
-  "Set and save `package-selected-packages' to VALUE."
-  (when value
-    (setq package-selected-packages value))
-  (if after-init-time
-      (customize-save-variable 'package-selected-packages package-selected-packages)
-    (add-hook 'after-init-hook #'package--save-selected-packages)))
-
 (defun package--user-selected-p (pkg)
   "Return non-nil if PKG is a package was installed by the user.
 PKG is a package name.
 This looks into `package-selected-packages', populating it first
 if it is still empty."
-  (unless (consp package-selected-packages)
-    (package--save-selected-packages (package--find-non-dependencies)))
-  (memq pkg package-selected-packages))
+  (unless (consp (multisession-value package-selected-packages))
+    (setf (multisession-value package-selected-packages)
+          (package--find-non-dependencies)))
+  (memq pkg (multisession-value package-selected-packages)))
 
 (defun package--get-deps (pkgs)
   (let ((seen '()))
@@ -1950,7 +1944,7 @@ package--removable-packages
   "Return a list of names of packages no longer needed.
 These are packages which are neither contained in
 `package-selected-packages' nor a dependency of one that is."
-  (let ((needed (package--get-deps package-selected-packages)))
+  (let ((needed (package--get-deps (multisession-value package-selected-packages))))
     (cl-loop for p in (mapcar #'car package-alist)
              unless (or (memq p needed)
                         ;; Do not auto-remove external packages.
@@ -2151,8 +2145,8 @@ package-install
                   (package-desc-name pkg)
                 pkg)))
     (unless (or dont-select (package--user-selected-p name))
-      (package--save-selected-packages
-       (cons name package-selected-packages)))
+      (setf (multisession-value package-selected-packages)
+       (cons name (multisession-value package-selected-packages))))
     (if-let* ((transaction
                (if (package-desc-p pkg)
                    (unless (package-installed-p pkg)
@@ -2284,8 +2278,8 @@ package-install-from-buffer
     ;; Install the package itself.
     (package-unpack pkg-desc)
     (unless (package--user-selected-p name)
-      (package--save-selected-packages
-       (cons name package-selected-packages)))
+      (setf (multisession-value package-selected-packages)
+       (cons name (multisession-value package-selected-packages))))
     (package--quickstart-maybe-refresh)
     pkg-desc))
 
@@ -2317,9 +2311,9 @@ package-install-selected-packages
   ;; We don't need to populate `package-selected-packages' before
   ;; using here, because the outcome is the same either way (nothing
   ;; gets installed).
-  (if (not package-selected-packages)
+  (if (not (multisession-value package-selected-packages))
       (message "`package-selected-packages' is empty, nothing to install")
-    (let* ((not-installed (seq-remove #'package-installed-p package-selected-packages))
+    (let* ((not-installed (seq-remove #'package-installed-p (multisession-value package-selected-packages)))
            (available (seq-filter (lambda (p) (assq p package-archive-contents)) not-installed))
            (difference (- (length not-installed) (length available))))
       (cond
@@ -2393,7 +2387,8 @@ package-delete
                ;; Don't deselect if this is an older version of an
                ;; upgraded package.
                (package--newest-p pkg-desc))
-      (package--save-selected-packages (remove name package-selected-packages)))
+      (setf (multisession-value package-selected-packages)
+            (remove name (multisession-value package-selected-packages))))
     (cond ((not (string-prefix-p (file-name-as-directory
                                   (expand-file-name package-user-dir))
                                  (expand-file-name dir)))
@@ -2485,7 +2480,7 @@ package-autoremove
   ;; If `package-selected-packages' is nil, it would make no sense to
   ;; try to populate it here, because then `package-autoremove' will
   ;; do absolutely nothing.
-  (when (or package-selected-packages
+  (when (or (multisession-value package-selected-packages)
             (yes-or-no-p
              (format-message
               "`package-selected-packages' is empty! Really remove ALL packages? ")))
@@ -3730,15 +3725,17 @@ package--update-selected-packages
 ADD and REMOVE must be disjoint lists of package names (or
 `package-desc' objects) to be added and removed to the selected
 packages list, respectively."
-  (dolist (p add)
-    (cl-pushnew (if (package-desc-p p) (package-desc-name p) p)
-                package-selected-packages))
-  (dolist (p remove)
-    (setq package-selected-packages
-          (remove (if (package-desc-p p) (package-desc-name p) p)
-                  package-selected-packages)))
-  (when (or add remove)
-    (package--save-selected-packages package-selected-packages)))
+  (let ((packages (multisession-value package-selected-packages)))
+    (dolist (p add)
+      (cl-pushnew (if (package-desc-p p) (package-desc-name p) p)
+                  packages))
+    (dolist (p remove)
+      (setq packages
+            (remove (if (package-desc-p p) (package-desc-name p) p)
+                    packages)))
+    (when (or add remove)
+      (setf (multisession-value package-selected-packages)
+            packages))))
 
 (defun package-menu-execute (&optional noquery)
   "Perform marked Package Menu actions.
@@ -3797,7 +3794,7 @@ package-menu-execute
           ;; Packages being upgraded are not marked as selected.
           (package--update-selected-packages .install .delete)
           (package-menu--perform-transaction install-list delete-list)
-          (when package-selected-packages
+          (when (multisession-value package-selected-packages)
             (if-let* ((removable (package--removable-packages)))
                 (message "Operation finished.  Packages that are no longer needed: %d.  Type `%s' to remove them"
                          (length removable)
-- 
2.37.2.382.g795ea8776b