From cdbd67742392349c941d0093057abc2c94e52940 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Wed, 14 Mar 2018 18:25:22 -0400 Subject: [PATCH] Allow use of package.el #444 This makes package.el commands safe to use in Doom, and prevents errors caused by unitialized state, by running package-initialize before you use a package.el command. --- core/autoload/packages.el | 160 ++++++++++++++++---------------------- core/core-packages.el | 20 +++-- 2 files changed, 77 insertions(+), 103 deletions(-) diff --git a/core/autoload/packages.el b/core/autoload/packages.el index 5add741da..577dee55c 100644 --- a/core/autoload/packages.el +++ b/core/autoload/packages.el @@ -6,11 +6,51 @@ (require 'package) (require 'async) +;;; Private functions +(defsubst doom--sort-alpha (it other) + (string-lessp (symbol-name (car it)) + (symbol-name (car other)))) + +(defun doom--packages-choose (prompt) + (let ((table (cl-loop for pkg in package-alist + unless (package-built-in-p (cdr pkg)) + collect (cons (package-desc-full-name (cdr pkg)) + (cdr pkg))))) + (cdr (assoc (completing-read prompt + (mapcar #'car table) + nil t) + table)))) + +(defmacro doom--condition-case! (&rest body) + `(condition-case-unless-debug ex + (condition-case ex2 + (progn ,@body) + ('file-error + (message! (bold (red " FILE ERROR: %s" (error-message-string ex2)))) + (message! " Trying again...") + (quiet! (doom-refresh-packages-maybe t)) + ,@body)) + ('user-error + (message! (bold (red " ERROR: %s" ex)))) + ('error + (doom--refresh-pkg-cache) + (message! (bold (red " FATAL ERROR: %s" ex)))))) + +(defun doom--refresh-pkg-cache () + "Clear the cache for `doom-refresh-packages-maybe'." + (setq doom--refreshed-p nil) + (doom-cache-set 'last-pkg-refresh nil)) + + +;; +;; Library +;; + ;;;###autoload -(defun doom-refresh-packages (&optional force-p) - "Refresh ELPA packages." +(defun doom-refresh-packages-maybe (&optional force-p) + "Refresh ELPA packages, if it hasn't been refreshed recently." (when force-p - (doom-refresh-clear-cache)) + (doom--refresh-pkg-cache)) (unless (or (doom-cache-get 'last-pkg-refresh) doom--refreshed-p) (condition-case-unless-debug ex @@ -19,16 +59,10 @@ (package-refresh-contents) (doom-cache-set 'last-pkg-refresh t 900)) ('error - (doom-refresh-clear-cache) + (doom--refresh-pkg-cache) (message "Failed to refresh packages: (%s) %s" (car ex) (error-message-string ex)))))) -;;;###autoload -(defun doom-refresh-clear-cache () - "Clear the cache for `doom-refresh-packages'." - (setq doom--refreshed-p nil) - (doom-cache-set 'last-pkg-refresh nil)) - ;;;###autoload (defun doom-package-backend (name &optional noerror) "Get which backend the package NAME was installed with. Can either be elpa or @@ -215,48 +249,6 @@ Used by `doom//packages-install'." (doom-package-different-recipe-p name))) collect desc)) -;;;###autoload -(defun doom*package-delete (desc &rest _) - "Update `quelpa-cache' upon a successful `package-delete'." - (let ((name (package-desc-name desc))) - (when (and (not (package-installed-p name)) - (assq name quelpa-cache)) - (map-delete quelpa-cache name) - (quelpa-save-cache) - (let ((path (expand-file-name (symbol-name name) quelpa-build-dir))) - (when (file-exists-p path) - (delete-directory path t)))))) - -;;; Private functions -(defsubst doom--sort-alpha (it other) - (string-lessp (symbol-name (car it)) - (symbol-name (car other)))) - -(defun doom--packages-choose (prompt) - (let ((table (cl-loop for pkg in package-alist - unless (package-built-in-p (cdr pkg)) - collect (cons (package-desc-full-name (cdr pkg)) - (cdr pkg))))) - (cdr (assoc (completing-read prompt - (mapcar #'car table) - nil t) - table)))) - -(defmacro doom--condition-case! (&rest body) - `(condition-case-unless-debug ex - (condition-case ex2 - (progn ,@body) - ('file-error - (message! (bold (red " FILE ERROR: %s" (error-message-string ex2)))) - (message! " Trying again...") - (quiet! (doom-refresh-packages t)) - ,@body)) - ('user-error - (message! (bold (red " ERROR: %s" ex)))) - ('error - (doom-refresh-clear-cache) - (message! (bold (red " FATAL ERROR: %s" ex)))))) - ;; ;; Main functions @@ -369,7 +361,7 @@ package.el as appropriate." (message! (yellow "Aborted!"))) (t - (doom-refresh-packages doom-debug-mode) + (doom-refresh-packages-maybe doom-debug-mode) (dolist (pkg packages) (message! "Installing %s" (car pkg)) (doom--condition-case! @@ -394,7 +386,7 @@ package.el as appropriate." "Interactive command for updating packages." (interactive) (message! "Looking for outdated packages...") - (doom-refresh-packages doom-debug-mode) + (doom-refresh-packages-maybe doom-debug-mode) (let ((packages (sort (doom-get-outdated-packages) #'doom--sort-alpha))) (cond ((not packages) (message! (green "Everything is up-to-date"))) @@ -475,38 +467,6 @@ package.el as appropriate." ;; Interactive commands ;; -;;;###autoload -(defalias 'doom/install-package #'package-install) - -;;;###autoload -(defun doom/reinstall-package (desc) - "Reinstalls package package with optional quelpa RECIPE (see `quelpa-recipe' for -an example; the package package can be omitted)." - (declare (interactive-only t)) - (interactive - (list (doom--packages-choose "Reinstall package: "))) - (let ((package (package-desc-name desc))) - (doom-delete-package package t) - (doom-install-package package (cdr (assq package doom-packages))))) - -;;;###autoload -(defun doom/delete-package (desc) - "Prompts the user with a list of packages and deletes the selected package. -Use this interactively. Use `doom-delete-package' for direct calls." - (declare (interactive-only t)) - (interactive - (list (doom--packages-choose "Delete package: "))) - (let ((package (package-desc-name desc))) - (if (package-installed-p package) - (if (y-or-n-p (format "%s will be deleted. Confirm?" package)) - (message "%s %s" - (if (doom-delete-package package t) - "Deleted" - "Failed to delete") - package) - (message "Aborted")) - (message "%s isn't installed" package)))) - ;;;###autoload (defun doom/update-package (pkg) "Prompts the user with a list of outdated packages and updates the selected @@ -521,6 +481,7 @@ calls." nil t) (user-error "All packages are up to date")))) (list (cdr (assq (car (assoc package package-alist)) packages))))) + (doom-initialize-packages) (cl-destructuring-bind (package old-version new-version) pkg (if-let* ((desc (doom-package-outdated-p package))) (let ((old-v-str (package-version-join old-version)) @@ -533,10 +494,25 @@ calls." (message "Aborted"))) (message "%s is up-to-date" package)))) + +;; +;; Advice +;; + ;;;###autoload -(defun doom/refresh-packages (&optional force-p) - "Synchronize package metadata with the sources in `package-archives'. If -FORCE-P (the universal argument) is set, ignore the cache." - (declare (interactive-only t)) - (interactive "P") - (doom-refresh-packages force-p)) +(defun doom*package-delete (desc &rest _) + "Update `quelpa-cache' upon a successful `package-delete'." + (let ((name (package-desc-name desc))) + (when (and (not (package-installed-p name)) + (assq name quelpa-cache)) + (map-delete quelpa-cache name) + (quelpa-save-cache) + (let ((path (expand-file-name (symbol-name name) quelpa-build-dir))) + (when (file-exists-p path) + (delete-directory path t)))))) + +;;;###autoload +(defun doom*initialize-packages (&rest _) + "TODO" + (unless doom-init-p + (doom-initialize-packages))) diff --git a/core/core-packages.el b/core/core-packages.el index 806d28d46..ae3e2192d 100644 --- a/core/core-packages.el +++ b/core/core-packages.el @@ -35,15 +35,7 @@ ;; just Emacs. Arguably, my config is still over-complicated, but shhh, it's ;; fine. Everything is fine. ;; -;; You should be able to use package.el commands without any conflicts, but to -;; be absolutely certain use the doom alternatives: -;; -;; + `package-install': `doom/install-package' -;; + `package-reinstall': `doom/reinstall-package' -;; + `package-delete': `doom/delete-package' -;; + `package-update': `doom/update-package' -;; + `package-autoremove': `doom//packages-autoremove' -;; + `package-refresh-contents': `doom/refresh-packages' +;; You should be able to use package.el commands without any conflicts. ;; ;; See core/autoload/packages.el for more functions. @@ -852,14 +844,20 @@ compiled packages.'" ;; -;; Package.el modifications +;; Make package.el cooperate with Doom ;; +(advice-add #'package-install :before #'doom*initialize-packages) +(advice-add #'package-reinstall :before #'doom*initialize-packages) +(advice-add #'package-delete :before #'doom*initialize-packages) +(advice-add #'package-refresh-contents :before #'doom*initialize-packages) + ;; Updates QUELPA after deleting a package (advice-add #'package-delete :after #'doom*package-delete) -;; It isn't safe to use `package-autoremove', so get rid of it +;; Replace with Doom variants (advice-add #'package-autoremove :override #'doom//packages-autoremove) +(advice-add #'package-install-selected-packages :override #'doom//packages-install) (provide 'core-packages) ;;; core-packages.el ends here