Fix packages with changed backend #222

Doom can't tell what backend a package was installed with, only whether it
is installed or not. This means if a package was installed with, say,
ELPA, then was changed to QUELPA, Doom wouldn't know.

Package management would fail. ELPA/QUELPA can't manage a package that
it didn't install.

This fix gives Doom that capability.
This commit is contained in:
Henrik Lissner 2017-11-05 16:04:31 +01:00
parent a6e0b3863d
commit 0c2b1b5a93
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395

View file

@ -27,21 +27,18 @@
(persistent-soft-store 'last-pkg-refresh nil "emacs")) (persistent-soft-store 'last-pkg-refresh nil "emacs"))
;;;###autoload ;;;###autoload
(defun doom-package-backend (name) (defun doom-package-backend (name &optional noerror)
"Get which backend the package NAME was installed with. Can either be elpa, "Get which backend the package NAME was installed with. Can either be elpa or
quelpa or nil (if not installed)." quelpa. Throws an error if NOERROR is nil and the package isn't installed."
(cl-assert (symbolp name) t) (cl-assert (symbolp name) t)
(doom-initialize-packages) (doom-initialize)
(cond ((let ((plist (cdr (assq name doom-packages)))) (cond ((and (or (quelpa-setup-p)
(and (not (plist-get plist :pin)) (error "Could not initialize quelpa"))
(or (quelpa-setup-p) (assq name quelpa-cache))
(error "Could not initialize quelpa"))
(or (assq name quelpa-cache)
(plist-get plist :recipe))))
'quelpa) 'quelpa)
((assq name package-alist) ((assq name package-alist)
'elpa) 'elpa)
(t ((not noerror)
(error "%s package not installed" name)))) (error "%s package not installed" name))))
;;;###autoload ;;;###autoload
@ -79,6 +76,18 @@ list of the package."
(doom-initialize-packages) (doom-initialize-packages)
(plist-get (cdr (assq name doom-packages)) prop)) (plist-get (cdr (assq name doom-packages)) prop))
;;;###autoload
(defun doom-package-different-backend-p (name)
"Return t if NAME (a package's symbol) has a new backend than what it was
installed with. Returns nil otherwise, or if package isn't installed."
(cl-assert (symbolp name) t)
(doom-initialize-packages)
(and (package-installed-p name)
(let* ((plist (cdr (assq name doom-packages)))
(old-backend (doom-package-backend name t))
(new-backend (if (plist-get plist :recipe) 'quelpa 'elpa)))
(not (eq old-backend new-backend)))))
;;;###autoload ;;;###autoload
(defun doom-get-packages (&optional installed-only-p) (defun doom-get-packages (&optional installed-only-p)
"Retrieves a list of explicitly installed packages (i.e. non-dependencies). "Retrieves a list of explicitly installed packages (i.e. non-dependencies).
@ -129,7 +138,8 @@ Used by `doom/packages-update'."
(let ((sym (car pkg))) (let ((sym (car pkg)))
(when (and (or (not (doom-package-prop sym :freeze)) (when (and (or (not (doom-package-prop sym :freeze))
include-frozen-p) include-frozen-p)
(not (doom-package-prop sym :ignore))) (not (doom-package-prop sym :ignore))
(not (doom-package-different-backend-p sym)))
(push sym (push sym
(if (eq (doom-package-backend sym) 'quelpa) (if (eq (doom-package-backend sym) 'quelpa)
quelpa-pkgs quelpa-pkgs
@ -158,7 +168,10 @@ Used by `doom/packages-autoremove'."
(doom-initialize-packages t) (doom-initialize-packages t)
(let ((package-selected-packages (let ((package-selected-packages
(append (mapcar #'car doom-packages) doom-core-packages))) (append (mapcar #'car doom-packages) doom-core-packages)))
(package--removable-packages))) (append (package--removable-packages)
(cl-loop for pkg in package-selected-packages
if (doom-package-different-backend-p pkg)
collect pkg))))
;;;###autoload ;;;###autoload
(defun doom-get-missing-packages (&optional include-ignored-p) (defun doom-get-missing-packages (&optional include-ignored-p)
@ -171,14 +184,15 @@ If INCLUDE-IGNORED-P is non-nil, includes missing packages that are ignored,
i.e. they have an :ignore property. i.e. they have an :ignore property.
Used by `doom/packages-install'." Used by `doom/packages-install'."
(cl-loop for pkgsym in (doom-get-packages) (cl-loop for desc in (doom-get-packages)
unless for (name . plist) = desc
(let ((pkg (car pkgsym))) if (and (or include-ignored-p
(or (assq pkg package-alist) (not (plist-get plist :ignore)))
(unless include-ignored-p (doom-package-prop pkg :ignore)) (or (plist-get plist :pin)
(and (not (plist-get (assq pkg doom-packages) :pin)) (not (assq name package--builtins)))
(assq pkg package--builtins)))) (or (not (assq name package-alist))
collect pkgsym)) (doom-package-different-backend-p name)))
collect desc))
;;;###autoload ;;;###autoload
(defun doom*package-delete (desc &rest _) (defun doom*package-delete (desc &rest _)
@ -238,6 +252,8 @@ Used by `doom/packages-install'."
example; the package name can be omitted)." example; the package name can be omitted)."
(doom-initialize-packages) (doom-initialize-packages)
(when (package-installed-p name) (when (package-installed-p name)
(when (doom-package-different-backend-p name)
(doom-delete-package name t))
(user-error "%s is already installed" name)) (user-error "%s is already installed" name))
(let ((plist (or plist (cdr (assq name doom-packages)))) (let ((plist (or plist (cdr (assq name doom-packages))))
(inhibit-message (not doom-debug-mode)) (inhibit-message (not doom-debug-mode))
@ -314,14 +330,20 @@ package.el as appropriate."
(y-or-n-p (y-or-n-p
(format "%s packages will be installed:\n\n%s\n\nProceed?" (format "%s packages will be installed:\n\n%s\n\nProceed?"
(length packages) (length packages)
(mapconcat (lambda (pkg) (mapconcat
(format "+ %s (%s)" (lambda (pkg)
(car pkg) (format "+ %s (%s)"
(if (plist-get (cdr pkg) :recipe) (car pkg)
"QUELPA" (cond ((doom-package-different-backend-p (car pkg))
"ELPA"))) (if (plist-get (cdr pkg) :recipe)
(sort (cl-copy-list packages) #'doom--sort-alpha) "ELPA -> QUELPA"
"\n"))))) "QUELPA -> ELPA"))
((plist-get (cdr pkg) :recipe)
"QUELPA")
(t
"ELPA"))))
(sort (cl-copy-list packages) #'doom--sort-alpha)
"\n")))))
(message! (yellow "Aborted!"))) (message! (yellow "Aborted!")))
(t (t
@ -396,12 +418,21 @@ package.el as appropriate."
(y-or-n-p (y-or-n-p
(format "%s packages will be deleted:\n\n%s\n\nProceed?" (format "%s packages will be deleted:\n\n%s\n\nProceed?"
(length packages) (length packages)
(mapconcat (lambda (sym) (format "+ %s (%s)" sym (mapconcat
(pcase (doom-package-backend sym) (lambda (sym)
('quelpa "QUELPA") (format
('elpa "ELPA")))) "+ %s (%s)"
(sort (cl-copy-list packages) #'string-lessp) sym
"\n"))))) (let ((backend (doom-package-backend sym)))
(if (doom-package-different-backend-p sym)
(if (eq backend 'quelpa)
"QUELPA->ELPA"
"ELPA->QUELPA")
(if (eq backend 'quelpa)
"QUELPA"
"ELPA")))))
(sort (cl-copy-list packages) #'string-lessp)
"\n")))))
(message! (yellow "Aborted!"))) (message! (yellow "Aborted!")))
(t (t
@ -417,6 +448,7 @@ package.el as appropriate."
(message! (bold (green "Finished!"))) (message! (bold (green "Finished!")))
(doom//reload-load-path))))) (doom//reload-load-path)))))
;;;###autoload ;;;###autoload
(defalias 'doom/install-package #'package-install) (defalias 'doom/install-package #'package-install)