Refactor package management: better feedback & bug fixes
This commit is contained in:
parent
10c28f2659
commit
323b2f6c2f
2 changed files with 140 additions and 96 deletions
|
@ -45,9 +45,9 @@ list of the package."
|
||||||
(new-version
|
(new-version
|
||||||
(pcase (doom-package-backend name)
|
(pcase (doom-package-backend name)
|
||||||
('quelpa
|
('quelpa
|
||||||
(let ((recipe (assq name quelpa-cache))
|
(let ((recipe (plist-get (cdr (assq 'rotate-text doom-packages)) :recipe))
|
||||||
(dir (expand-file-name (symbol-name name) quelpa-build-dir))
|
(dir (expand-file-name (symbol-name name) quelpa-build-dir))
|
||||||
(inhibit-message t))
|
(inhibit-message (not doom-debug-mode)))
|
||||||
(if-let (ver (quelpa-checkout recipe dir))
|
(if-let (ver (quelpa-checkout recipe dir))
|
||||||
(version-to-list ver)
|
(version-to-list ver)
|
||||||
old-version)))
|
old-version)))
|
||||||
|
@ -127,22 +127,36 @@ Used by `doom/packages-install'."
|
||||||
(doom-get-packages)))
|
(doom-get-packages)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom*package-delete (name &rest _)
|
(defun doom*package-delete (desc &rest _)
|
||||||
"Update `quelpa-cache' upon a successful `package-delete'."
|
"Update `quelpa-cache' upon a successful `package-delete'."
|
||||||
(when (and (not (package-installed-p name))
|
(let ((name (package-desc-name desc)))
|
||||||
(quelpa-setup-p)
|
(when (and (not (package-installed-p name))
|
||||||
(assq name quelpa-cache))
|
(quelpa-setup-p)
|
||||||
(setq quelpa-cache (assq-delete-all name quelpa-cache))
|
(assq name quelpa-cache))
|
||||||
(quelpa-save-cache)
|
(setq quelpa-cache (assq-delete-all name quelpa-cache))
|
||||||
(let ((path (expand-file-name (symbol-name name) quelpa-build-dir)))
|
(quelpa-save-cache)
|
||||||
(when (file-exists-p path)
|
(let ((path (expand-file-name (symbol-name name) quelpa-build-dir)))
|
||||||
(delete-directory path t)))))
|
(when (file-exists-p path)
|
||||||
|
(delete-directory path t))))))
|
||||||
|
|
||||||
;;; Private functions
|
;;; Private functions
|
||||||
(defsubst doom--sort-alpha (it other)
|
(defsubst doom--sort-alpha (it other)
|
||||||
(string-lessp (symbol-name (car it))
|
(string-lessp (symbol-name (car it))
|
||||||
(symbol-name (car other))))
|
(symbol-name (car other))))
|
||||||
|
|
||||||
|
(defun doom--packages-choose (prompt)
|
||||||
|
(doom-initialize)
|
||||||
|
(let* ((table (mapcar
|
||||||
|
(lambda (p) (cons (package-desc-full-name p) p))
|
||||||
|
(delq nil
|
||||||
|
(mapcar (lambda (p) (unless (package-built-in-p p) p))
|
||||||
|
(apply #'append (mapcar #'cdr package-alist))))))
|
||||||
|
(name (completing-read
|
||||||
|
prompt
|
||||||
|
(mapcar #'car table)
|
||||||
|
nil t)))
|
||||||
|
(cdr (assoc name table))))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Main functions
|
;; Main functions
|
||||||
|
@ -160,8 +174,9 @@ example; the package name can be omitted)."
|
||||||
(recipe (plist-get plist :recipe)))
|
(recipe (plist-get plist :recipe)))
|
||||||
(cond (recipe (quelpa recipe))
|
(cond (recipe (quelpa recipe))
|
||||||
(t (package-install name))))
|
(t (package-install name))))
|
||||||
(cl-pushnew (cons name plist) doom-packages :test #'eq :key #'car)
|
(when (package-installed-p name)
|
||||||
(package-installed-p name))
|
(cl-pushnew (cons name plist) doom-packages :test #'eq :key #'car)
|
||||||
|
t))
|
||||||
|
|
||||||
(defun doom-update-package (name)
|
(defun doom-update-package (name)
|
||||||
"Updates package NAME if it is out of date, using quelpa or package.el as
|
"Updates package NAME if it is out of date, using quelpa or package.el as
|
||||||
|
@ -188,6 +203,11 @@ appropriate."
|
||||||
(unless (package-installed-p name)
|
(unless (package-installed-p name)
|
||||||
(user-error "%s isn't installed" name))
|
(user-error "%s isn't installed" name))
|
||||||
(let ((inhibit-message (not doom-debug-mode)))
|
(let ((inhibit-message (not doom-debug-mode)))
|
||||||
|
(unless (quelpa-setup-p)
|
||||||
|
(error "Could not initialize QUELPA"))
|
||||||
|
(when (assq name quelpa-cache)
|
||||||
|
(setq quelpa-cache (assq-delete-all name quelpa-cache))
|
||||||
|
(quelpa-save-cache))
|
||||||
(package-delete (cadr (assq name package-alist)) force-p))
|
(package-delete (cadr (assq name package-alist)) force-p))
|
||||||
(not (package-installed-p name)))
|
(not (package-installed-p name)))
|
||||||
|
|
||||||
|
@ -219,26 +239,29 @@ appropriate."
|
||||||
(message! (yellow "Aborted!")))
|
(message! (yellow "Aborted!")))
|
||||||
|
|
||||||
(t
|
(t
|
||||||
|
(doom-refresh-packages)
|
||||||
(dolist (pkg packages)
|
(dolist (pkg packages)
|
||||||
|
(message! "Installing %s" (car pkg))
|
||||||
(condition-case ex
|
(condition-case ex
|
||||||
(message!
|
(progn
|
||||||
(cond ((package-installed-p (car pkg))
|
(message!
|
||||||
(dark (white "Skipped %%%%s (already installed)")))
|
" %s%s"
|
||||||
((doom-install-package (car pkg) (cdr pkg))
|
(cond ((package-installed-p (car pkg))
|
||||||
(green "Installed %%s (%%s)"))
|
(dark (white "ALREADY INSTALLED")))
|
||||||
(t
|
((doom-install-package (car pkg) (cdr pkg))
|
||||||
(red "Failed to install %%s (%%s)")))
|
(green "DONE"))
|
||||||
(concat (symbol-name (car pkg))
|
(t
|
||||||
(when (plist-member (cdr pkg) :pin)
|
(red "FAILED")))
|
||||||
(format " [pinned: %s]" (plist-get (cdr pkg) :pin))))
|
(if (plist-member (cdr pkg) :pin)
|
||||||
(pcase (doom-package-backend (car pkg))
|
(format " [pinned: %s]" (plist-get (cdr pkg) :pin))
|
||||||
('quelpa "QUELPA")
|
"")))
|
||||||
('elpa "ELPA")))
|
|
||||||
('user-error
|
('user-error
|
||||||
(message! (bold (red "Error installing %s: %s" (car pkg) ex))))))
|
(message! (bold (red " ERROR: %s" ex ))))
|
||||||
|
('error
|
||||||
|
(message! (bold (red " FATAL ERROR: %s" ex )))))))
|
||||||
|
|
||||||
(message! (bold (green "Finished!")))
|
(message! (bold (green "Finished!")))
|
||||||
(doom/reload)))))
|
(doom/reload))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/packages-update ()
|
(defun doom/packages-update ()
|
||||||
|
@ -267,16 +290,19 @@ appropriate."
|
||||||
(message! (yellow "Aborted!")))
|
(message! (yellow "Aborted!")))
|
||||||
|
|
||||||
(t
|
(t
|
||||||
|
(doom-refresh-packages)
|
||||||
(dolist (pkg packages)
|
(dolist (pkg packages)
|
||||||
|
(message! "Updating %s" (car pkg))
|
||||||
(condition-case ex
|
(condition-case ex
|
||||||
(message!
|
(message!
|
||||||
(let ((result (doom-update-package (car pkg))))
|
(let ((result (doom-update-package (car pkg))))
|
||||||
(color (if result 'green 'red)
|
(color (if result 'green 'red)
|
||||||
"%s %s"
|
" %s"
|
||||||
(if result "Updated" "Failed to update")
|
(if result "DONE" "FAILED"))))
|
||||||
(car pkg))))
|
|
||||||
('user-error
|
('user-error
|
||||||
(message! (bold (red "Error updating %s: %s" (car pkg) ex))))))
|
(message! (bold (red " ERROR: %s" ex))))
|
||||||
|
('error
|
||||||
|
(message! (bold (red " FATAL ERROR: %s" ex))))))
|
||||||
|
|
||||||
(message! (bold (green "Finished!")))
|
(message! (bold (green "Finished!")))
|
||||||
(doom/reload)))))
|
(doom/reload)))))
|
||||||
|
@ -293,7 +319,10 @@ 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" sym))
|
(mapconcat (lambda (sym) (format "+ %s (%s)" sym
|
||||||
|
(pcase (doom-package-backend sym)
|
||||||
|
('quelpa "QUELPA")
|
||||||
|
('elpa "ELPA"))))
|
||||||
(sort (cl-copy-list packages) #'string-lessp)
|
(sort (cl-copy-list packages) #'string-lessp)
|
||||||
"\n")))))
|
"\n")))))
|
||||||
(message! (yellow "Aborted!")))
|
(message! (yellow "Aborted!")))
|
||||||
|
@ -305,10 +334,12 @@ appropriate."
|
||||||
(let ((result (doom-delete-package pkg t)))
|
(let ((result (doom-delete-package pkg t)))
|
||||||
(color (if result 'green 'red)
|
(color (if result 'green 'red)
|
||||||
"%s %s"
|
"%s %s"
|
||||||
(if result "Deleted" "Failed to delete")
|
(if result "Removed" "Failed to remove")
|
||||||
pkg)))
|
pkg)))
|
||||||
('user-error
|
('user-error
|
||||||
(message! (bold (red "Error deleting %s: %s" pkg ex))))))
|
(message! (bold (red " ERROR: %s" ex))))
|
||||||
|
('error
|
||||||
|
(message! (bold (red " FATAL ERROR: %s" ex))))))
|
||||||
|
|
||||||
(message! (bold (green "Finished!")))
|
(message! (bold (green "Finished!")))
|
||||||
(doom/reload)))))
|
(doom/reload)))))
|
||||||
|
@ -317,45 +348,54 @@ appropriate."
|
||||||
(defalias 'doom/install-package #'package-install)
|
(defalias 'doom/install-package #'package-install)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/delete-package (package)
|
(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.
|
"Prompts the user with a list of packages and deletes the selected package.
|
||||||
Use this interactively. Use `doom-delete-package' for direct calls."
|
Use this interactively. Use `doom-delete-package' for direct calls."
|
||||||
(declare (interactive-only t))
|
(declare (interactive-only t))
|
||||||
(interactive
|
(interactive
|
||||||
(progn
|
(list (doom--packages-choose "Delete package: ")))
|
||||||
(doom-initialize)
|
(let ((package (package-desc-name desc)))
|
||||||
(list (completing-read
|
(if (package-installed-p package)
|
||||||
"Delete package: "
|
(if (y-or-n-p (format "%s will be deleted. Confirm?" package))
|
||||||
(cl-remove-if #'package-built-in-p package-alist :key #'car)
|
(message "%s %s"
|
||||||
nil t))))
|
(if (doom-delete-package package t) "Deleted" "Failed to delete")
|
||||||
(if (package-installed-p package)
|
package)
|
||||||
(if (y-or-n-p (format "%s will be deleted. Confirm?" package))
|
(message "Aborted"))
|
||||||
(message "%s %s"
|
(message "%s isn't installed" package))))
|
||||||
(if (doom-delete-package package) "Deleted" "Failed to delete")
|
|
||||||
pkg)
|
|
||||||
(message "Aborted"))
|
|
||||||
(message "%s isn't installed" package)))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/update-package (package)
|
(defun doom/update-package (pkg)
|
||||||
"Prompts the user with a list of outdated packages and updates the selected
|
"Prompts the user with a list of outdated packages and updates the selected
|
||||||
package. Use this interactively. Use `doom-update-package' for direct
|
package. Use this interactively. Use `doom-update-package' for direct
|
||||||
calls."
|
calls."
|
||||||
(declare (interactive-only t))
|
(declare (interactive-only t))
|
||||||
(interactive
|
(interactive
|
||||||
(let ((packages (doom-get-outdated-packages)))
|
(let* ((packages (doom-get-outdated-packages))
|
||||||
(list
|
(package (if packages
|
||||||
(if packages
|
(completing-read "Update package: "
|
||||||
(completing-read "Update package: "
|
(mapcar #'car packages)
|
||||||
(mapcar #'symbol-name (mapcar #'car packages)))
|
nil t)
|
||||||
(user-error "All packages are up-to-date")))))
|
(user-error "All packages are up to date"))))
|
||||||
(if-let (desc (doom-package-outdated-p (intern package)))
|
(list (cdr (assq (car (assoc package package-alist)) packages)))))
|
||||||
(if (y-or-n-p (format "%s will be updated from %s to %s. Update?"
|
(destructuring-bind (package old-version new-version) pkg
|
||||||
(car desc)
|
(if-let (desc (doom-package-outdated-p package))
|
||||||
(package-version-join (cadr desc))
|
(let ((old-v-str (package-version-join old-version))
|
||||||
(package-version-join (cl-caddr desc))))
|
(new-v-str (package-version-join new-version)))
|
||||||
(message "%s %s"
|
(if (y-or-n-p (format "%s will be updated from %s to %s. Update?"
|
||||||
(if (doom-update-package package) "Updated" "Failed to update")
|
package old-v-str new-v-str))
|
||||||
pkg)
|
(message "%s %s (%s => %s)"
|
||||||
(message "Aborted"))
|
(if (doom-update-package package) "Updated" "Failed to update")
|
||||||
(message "%s is up-to-date" package)))
|
package old-v-str new-v-str)
|
||||||
|
(message "Aborted")))
|
||||||
|
(message "%s is up-to-date" package))))
|
||||||
|
|
|
@ -1,39 +1,40 @@
|
||||||
;;; core-packages.el
|
;;; core-packages.el
|
||||||
|
|
||||||
;; Emacs package management is opinionated. Unfortunately, so am I. With the
|
;; Emacs package management is opinionated. Unfortunately, so am I. I've bound
|
||||||
;; help of `use-package', `quelpa' and package.el, DOOM Emacs manages its
|
;; together `use-package', `quelpa' and package.el to create my own,
|
||||||
;; plugins and their dependencies through `doom/packages-install',
|
;; rolling-release, lazily-loaded package management system for Emacs.
|
||||||
;; `doom/packages-update' and `doom/packages-autoremove', which can be called
|
|
||||||
;; via `make' on the command line (make {install,update,autoremove}).
|
|
||||||
;;
|
;;
|
||||||
;; My config is divided into two parts: configuration and packages.el files.
|
;; The three key commands are `doom/packages-install', `doom/packages-update'
|
||||||
;; You'll find packages.el files in each DOOM module (in `doom-modules-dir') and
|
;; and `doom/packages-autoremove', which can be called via `make' on the command
|
||||||
;; one in `doom-core-dir'. When executed, they fill `doom-packages' and
|
;; line (make {install,update,autoremove}). These read packages.el files in each
|
||||||
;; `doom-modules', which are necessary for DOOM to extrapolate all kinds of
|
;; activated module in `doom-modules-dir' (and one in `doom-core-dir') which
|
||||||
;; information about plugins.
|
;; tell DOOM what plugins to install and where from.
|
||||||
;;
|
;;
|
||||||
;; Why all the trouble? Because:
|
;; Why all the trouble? Because:
|
||||||
;; 1. Scriptability: I want an alternative to package.el's list-packages
|
;; 1. Scriptability: I live in the command line. I want a programmable
|
||||||
;; interface for updating and installing packages.
|
;; alternative to `list-packages' for updating and installing packages.
|
||||||
;; 2. Flexibility: I sometimes want packages from sources other than ELPA. Like
|
;; 2. Flexibility: I want packages from sources other than ELPA. Like github or
|
||||||
;; github or the Emacs wiki, because certain plugins are out-of-date through
|
;; the Emacs wiki, because certain plugins are out-of-date through official
|
||||||
;; official channels, have changed hands unofficially, or simply haven't been
|
;; channels, have changed hands, or simply aren't in any ELPA repo.
|
||||||
;; submitted to an ELPA repo yet.
|
;; 3. Stability: I used Cask before this. It would error out with cyrptic errors
|
||||||
;; 3. Stability: I don't want to worry that each time I use my package
|
;; depending on the version of Emacs I used and the alignment of the planets.
|
||||||
;; manager something might inexplicably go wrong. Cask, I'm looking at you.
|
;; No more.
|
||||||
;; 4. Performance: A minor point, but it helps startup performance not to do
|
;; 4. Performance: A minor point, but this system is lazy-loaded (more so if you
|
||||||
;; package.el initialization and package installation checks at startup.
|
;; byte-compile). Not having to initialize package.el (or check that your
|
||||||
;; 5. Simplicity: Without Cask, I have no external dependencies to worry about
|
;; packages are installed) every time you start up Emacs affords us precious
|
||||||
;; (unless you count make). DOOM handles itself. Arguably, my emacs.d is
|
;; seconds.
|
||||||
;; overcomplicated, but configuring is simpler as a result (well, for me
|
;; 5. Simplicity: No Cask, no external dependencies (unless you count make).
|
||||||
;; anyway :P).
|
;; Arguably, this means my config is overcomplicated, but shhh, it's alright.
|
||||||
|
;; Everything is fine.
|
||||||
;;
|
;;
|
||||||
;; It should be safe to use package.el functionality, however, avoid
|
;; Technically, package.el commands should still work. To be absolutely sure,
|
||||||
;; `package-autoremove' as it will not reliably select the correct packages to
|
;; use the doom alternatives:
|
||||||
;; delete.
|
|
||||||
;;
|
;;
|
||||||
;; For complete certainty, I've provided DOOM alternatives of package commands,
|
;; + `package-install': `doom/install-package'
|
||||||
;; like `doom/install-package', `doom/delete-package' & `doom/update-packages'.
|
;; + `package-reinstall': `doom/reinstall-package'
|
||||||
|
;; + `package-delete': `doom/delete-package'
|
||||||
|
;; + `package-update': `doom/update-package'
|
||||||
|
;; + `package-autoremove': `doom/packages-autoremove'
|
||||||
;;
|
;;
|
||||||
;; See core/autoload/packages.el for more functions.
|
;; See core/autoload/packages.el for more functions.
|
||||||
|
|
||||||
|
@ -537,5 +538,8 @@ package files."
|
||||||
;; Updates QUELPA after deleting a package
|
;; Updates QUELPA after deleting a package
|
||||||
(advice-add #'package-delete :after #'doom*package-delete)
|
(advice-add #'package-delete :after #'doom*package-delete)
|
||||||
|
|
||||||
|
;; It isn't safe to use `package-autoremove', so get rid of it
|
||||||
|
(advice-add #'package-autoremove :override #'doom/packages-autoremove)
|
||||||
|
|
||||||
(provide 'core-packages)
|
(provide 'core-packages)
|
||||||
;;; core-packages.el ends here
|
;;; core-packages.el ends here
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue