2017-06-08 11:47:56 +02:00
|
|
|
;;; core/autoload/packages.el -*- lexical-binding: t; -*-
|
2017-02-02 19:15:58 -05:00
|
|
|
|
2017-12-22 15:25:02 -05:00
|
|
|
(require 'use-package)
|
|
|
|
(require 'quelpa)
|
|
|
|
|
2017-04-04 12:29:34 -04:00
|
|
|
(defvar doom--last-refresh nil)
|
|
|
|
|
2017-02-03 07:58:16 -05:00
|
|
|
;;;###autoload
|
2017-05-19 22:29:47 +02:00
|
|
|
(defun doom-refresh-packages (&optional force-p)
|
2017-02-03 07:58:16 -05:00
|
|
|
"Refresh ELPA packages."
|
2017-05-27 18:29:32 +02:00
|
|
|
(when force-p
|
2017-05-19 22:29:47 +02:00
|
|
|
(doom-refresh-clear-cache))
|
2017-06-06 12:01:10 +02:00
|
|
|
(unless (or (persistent-soft-fetch 'last-pkg-refresh "emacs")
|
2017-11-08 22:49:11 +01:00
|
|
|
doom--refreshed-p)
|
2017-06-14 12:17:36 +02:00
|
|
|
(condition-case-unless-debug ex
|
2017-05-19 22:29:47 +02:00
|
|
|
(progn
|
2017-05-27 18:29:32 +02:00
|
|
|
(message "Refreshing package archives")
|
2017-07-04 12:26:27 +02:00
|
|
|
(package-refresh-contents)
|
2017-06-08 11:47:56 +02:00
|
|
|
(persistent-soft-store 'last-pkg-refresh t "emacs" 900))
|
2017-06-14 12:17:36 +02:00
|
|
|
('error
|
2017-05-27 18:29:32 +02:00
|
|
|
(doom-refresh-clear-cache)
|
2017-06-14 12:17:36 +02:00
|
|
|
(message "Failed to refresh packages: (%s) %s"
|
|
|
|
(car ex) (error-message-string ex))))))
|
2017-05-19 22:29:47 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun doom-refresh-clear-cache ()
|
|
|
|
"Clear the cache for `doom-refresh-packages'."
|
2017-11-08 22:49:11 +01:00
|
|
|
(setq doom--refreshed-p nil)
|
2017-05-19 22:29:47 +02:00
|
|
|
(persistent-soft-store 'last-pkg-refresh nil "emacs"))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-11-05 16:04:31 +01:00
|
|
|
(defun doom-package-backend (name &optional noerror)
|
|
|
|
"Get which backend the package NAME was installed with. Can either be elpa or
|
|
|
|
quelpa. Throws an error if NOERROR is nil and the package isn't installed."
|
2017-06-14 12:17:36 +02:00
|
|
|
(cl-assert (symbolp name) t)
|
2017-11-05 16:04:31 +01:00
|
|
|
(cond ((and (or (quelpa-setup-p)
|
|
|
|
(error "Could not initialize quelpa"))
|
|
|
|
(assq name quelpa-cache))
|
2017-02-04 21:07:54 -05:00
|
|
|
'quelpa)
|
|
|
|
((assq name package-alist)
|
2017-05-14 09:49:09 +02:00
|
|
|
'elpa)
|
2017-12-22 15:25:02 -05:00
|
|
|
((package-built-in-p name)
|
|
|
|
'emacs)
|
2017-11-05 16:04:31 +01:00
|
|
|
((not noerror)
|
2017-11-13 18:03:36 +01:00
|
|
|
(error "%s package is not installed" name))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun doom-package-outdated-p (name)
|
|
|
|
"Determine whether NAME (a symbol) is outdated or not. If outdated, returns a
|
|
|
|
list, whose car is NAME, and cdr the current version list and latest version
|
|
|
|
list of the package."
|
2017-06-14 12:17:36 +02:00
|
|
|
(cl-assert (symbolp name) t)
|
2017-06-02 22:28:46 +02:00
|
|
|
(doom-initialize-packages)
|
2017-12-10 14:49:52 -05:00
|
|
|
(when-let* ((desc (cadr (assq name package-alist))))
|
2017-08-06 16:30:53 +02:00
|
|
|
(let* ((old-version (package-desc-version desc))
|
2017-02-11 00:46:42 -05:00
|
|
|
(new-version
|
|
|
|
(pcase (doom-package-backend name)
|
|
|
|
('quelpa
|
2017-06-02 22:28:14 +02:00
|
|
|
(let ((recipe (plist-get (cdr (assq name doom-packages)) :recipe))
|
2017-02-19 06:59:55 -05:00
|
|
|
(dir (expand-file-name (symbol-name name) quelpa-build-dir))
|
2017-06-03 21:29:33 +02:00
|
|
|
(inhibit-message (not doom-debug-mode))
|
|
|
|
(quelpa-upgrade-p t))
|
2017-12-10 14:49:52 -05:00
|
|
|
(if-let* ((ver (quelpa-checkout recipe dir)))
|
2017-02-11 00:46:42 -05:00
|
|
|
(version-to-list ver)
|
|
|
|
old-version)))
|
|
|
|
('elpa
|
|
|
|
(let ((desc (cadr (assq name package-archive-contents))))
|
|
|
|
(when (package-desc-p desc)
|
|
|
|
(package-desc-version desc)))))))
|
|
|
|
(when (and (listp old-version) (listp new-version)
|
|
|
|
(version-list-< old-version new-version))
|
|
|
|
(list name old-version new-version)))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-06-05 14:21:07 +02:00
|
|
|
;;;###autoload
|
2017-06-14 12:35:31 +02:00
|
|
|
(defun doom-package-prop (name prop)
|
|
|
|
"Return PROPerty in NAME's plist."
|
|
|
|
(cl-assert (symbolp name) t)
|
|
|
|
(cl-assert (keywordp prop) t)
|
2017-06-05 14:21:07 +02:00
|
|
|
(doom-initialize-packages)
|
2017-06-14 12:35:31 +02:00
|
|
|
(plist-get (cdr (assq name doom-packages)) prop))
|
2017-06-05 14:21:07 +02:00
|
|
|
|
2017-11-05 16:04:31 +01:00
|
|
|
;;;###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)))
|
2017-12-22 15:25:02 -05:00
|
|
|
(old-backend (doom-package-backend name 'noerror))
|
2017-11-05 16:04:31 +01:00
|
|
|
(new-backend (if (plist-get plist :recipe) 'quelpa 'elpa)))
|
|
|
|
(not (eq old-backend new-backend)))))
|
|
|
|
|
2017-02-03 07:58:16 -05:00
|
|
|
;;;###autoload
|
2017-07-13 13:41:54 +02:00
|
|
|
(defun doom-get-packages (&optional installed-only-p)
|
2017-02-03 07:58:16 -05:00
|
|
|
"Retrieves a list of explicitly installed packages (i.e. non-dependencies).
|
|
|
|
Each element is a cons cell, whose car is the package symbol and whose cdr is
|
|
|
|
the quelpa recipe (if any).
|
|
|
|
|
|
|
|
BACKEND can be 'quelpa or 'elpa, and will instruct this function to return only
|
2017-02-19 06:59:55 -05:00
|
|
|
the packages relevant to that backend.
|
|
|
|
|
|
|
|
Warning: this function is expensive; it re-evaluates all of doom's config files.
|
2017-07-13 13:41:54 +02:00
|
|
|
Be careful not to use it in a loop.
|
|
|
|
|
|
|
|
If INSTALLED-ONLY-P, only return packages that are installed."
|
2017-02-11 00:46:42 -05:00
|
|
|
(doom-initialize-packages t)
|
2017-06-08 11:47:56 +02:00
|
|
|
(cl-loop with packages = (append doom-core-packages (mapcar #'car doom-packages))
|
|
|
|
for sym in (cl-delete-duplicates packages)
|
2017-07-13 13:41:54 +02:00
|
|
|
if (and (or (not installed-only-p)
|
|
|
|
(package-installed-p sym))
|
|
|
|
(or (assq sym doom-packages)
|
|
|
|
(and (assq sym package-alist)
|
|
|
|
(list sym))))
|
2017-06-08 11:47:56 +02:00
|
|
|
collect it))
|
2017-02-19 06:59:55 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-04-04 22:17:33 -04:00
|
|
|
(defun doom-get-depending-on (name)
|
2017-02-19 06:59:55 -05:00
|
|
|
"Return a list of packages that depend on the package named NAME."
|
2017-12-10 14:49:52 -05:00
|
|
|
(when-let* ((desc (cadr (assq name package-alist))))
|
2017-04-17 02:17:10 -04:00
|
|
|
(mapcar #'package-desc-name (package--used-elsewhere-p desc nil t))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-04-04 22:17:33 -04:00
|
|
|
;;;###autoload
|
|
|
|
(defun doom-get-dependencies-for (name &optional only)
|
|
|
|
"Return a list of dependencies for a package."
|
|
|
|
(package--get-deps name only))
|
|
|
|
|
2017-02-03 07:58:16 -05:00
|
|
|
;;;###autoload
|
2017-06-05 14:21:07 +02:00
|
|
|
(defun doom-get-outdated-packages (&optional include-frozen-p)
|
2017-02-11 00:46:42 -05:00
|
|
|
"Return a list of packages that are out of date. Each element is a list,
|
|
|
|
containing (PACKAGE-SYMBOL OLD-VERSION-LIST NEW-VERSION-LIST).
|
2017-02-09 04:25:32 -05:00
|
|
|
|
2017-06-05 14:21:07 +02:00
|
|
|
If INCLUDE-FROZEN-P is non-nil, check frozen packages as well.
|
|
|
|
|
2017-11-13 17:58:16 +01:00
|
|
|
Used by `doom//packages-update'."
|
2017-06-21 16:09:58 +02:00
|
|
|
(let (quelpa-pkgs elpa-pkgs)
|
2017-06-24 02:07:53 +02:00
|
|
|
;; Separate quelpa from elpa packages
|
2017-07-13 13:41:54 +02:00
|
|
|
(dolist (pkg (doom-get-packages t))
|
2017-06-21 16:09:58 +02:00
|
|
|
(let ((sym (car pkg)))
|
|
|
|
(when (and (or (not (doom-package-prop sym :freeze))
|
2017-06-08 11:47:56 +02:00
|
|
|
include-frozen-p)
|
2017-11-05 16:04:31 +01:00
|
|
|
(not (doom-package-prop sym :ignore))
|
|
|
|
(not (doom-package-different-backend-p sym)))
|
2017-06-21 16:09:58 +02:00
|
|
|
(push sym
|
|
|
|
(if (eq (doom-package-backend sym) 'quelpa)
|
|
|
|
quelpa-pkgs
|
|
|
|
elpa-pkgs)))))
|
2017-11-05 00:57:26 +01:00
|
|
|
;; The bottleneck in this process is quelpa's version checks, so check them
|
|
|
|
;; asynchronously.
|
|
|
|
(let (futures)
|
|
|
|
(dolist (pkg quelpa-pkgs)
|
|
|
|
(debug! "New thread for: %s" pkg)
|
2017-06-21 16:09:58 +02:00
|
|
|
(push (async-start
|
|
|
|
`(lambda ()
|
2017-09-05 12:40:54 +02:00
|
|
|
(setq user-emacs-directory ,user-emacs-directory)
|
2017-06-21 16:09:58 +02:00
|
|
|
(let ((noninteractive t))
|
|
|
|
(load ,(expand-file-name "core.el" doom-core-dir)))
|
2017-11-05 00:57:26 +01:00
|
|
|
(doom-package-outdated-p ',pkg)))
|
2017-06-21 16:09:58 +02:00
|
|
|
futures))
|
2017-12-22 15:25:02 -05:00
|
|
|
(delq nil
|
|
|
|
(append (mapcar #'doom-package-outdated-p elpa-pkgs)
|
|
|
|
(mapcar #'async-get (reverse futures)))))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-02-02 19:15:58 -05:00
|
|
|
;;;###autoload
|
2017-02-03 07:58:16 -05:00
|
|
|
(defun doom-get-orphaned-packages ()
|
2017-02-09 04:25:32 -05:00
|
|
|
"Return a list of symbols representing packages that are no longer needed or
|
|
|
|
depended on.
|
|
|
|
|
2017-11-13 17:58:16 +01:00
|
|
|
Used by `doom//packages-autoremove'."
|
2017-02-11 00:46:42 -05:00
|
|
|
(doom-initialize-packages t)
|
2017-02-19 06:59:55 -05:00
|
|
|
(let ((package-selected-packages
|
2017-04-17 02:17:10 -04:00
|
|
|
(append (mapcar #'car doom-packages) doom-core-packages)))
|
2017-11-05 16:04:31 +01:00
|
|
|
(append (package--removable-packages)
|
|
|
|
(cl-loop for pkg in package-selected-packages
|
2017-12-22 04:02:47 -05:00
|
|
|
if (and (doom-package-different-backend-p pkg)
|
|
|
|
(not (package-built-in-p pkg)))
|
2017-11-05 16:04:31 +01:00
|
|
|
collect pkg))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-06-05 14:21:07 +02:00
|
|
|
(defun doom-get-missing-packages (&optional include-ignored-p)
|
2017-04-04 22:17:42 -04:00
|
|
|
"Return a list of requested packages that aren't installed or built-in, but
|
|
|
|
are enabled (with a `package!' directive). Each element is a list whose CAR is
|
|
|
|
the package symbol, and whose CDR is a plist taken from that package's
|
|
|
|
`package!' declaration.
|
2017-02-09 04:25:32 -05:00
|
|
|
|
2017-06-05 14:21:07 +02:00
|
|
|
If INCLUDE-IGNORED-P is non-nil, includes missing packages that are ignored,
|
|
|
|
i.e. they have an :ignore property.
|
|
|
|
|
2017-11-13 17:58:16 +01:00
|
|
|
Used by `doom//packages-install'."
|
2017-11-05 16:04:31 +01:00
|
|
|
(cl-loop for desc in (doom-get-packages)
|
|
|
|
for (name . plist) = desc
|
|
|
|
if (and (or include-ignored-p
|
|
|
|
(not (plist-get plist :ignore)))
|
|
|
|
(or (plist-get plist :pin)
|
|
|
|
(not (assq name package--builtins)))
|
|
|
|
(or (not (assq name package-alist))
|
|
|
|
(doom-package-different-backend-p name)))
|
|
|
|
collect desc))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-02-03 19:20:47 -05:00
|
|
|
;;;###autoload
|
2017-05-19 02:57:39 +02:00
|
|
|
(defun doom*package-delete (desc &rest _)
|
2017-02-06 00:13:24 -05:00
|
|
|
"Update `quelpa-cache' upon a successful `package-delete'."
|
2017-05-19 02:57:39 +02:00
|
|
|
(let ((name (package-desc-name desc)))
|
|
|
|
(when (and (not (package-installed-p name))
|
|
|
|
(quelpa-setup-p)
|
|
|
|
(assq name quelpa-cache))
|
|
|
|
(setq quelpa-cache (assq-delete-all name quelpa-cache))
|
|
|
|
(quelpa-save-cache)
|
|
|
|
(let ((path (expand-file-name (symbol-name name) quelpa-build-dir)))
|
|
|
|
(when (file-exists-p path)
|
|
|
|
(delete-directory path t))))))
|
2017-02-03 19:20:47 -05:00
|
|
|
|
2017-02-19 06:59:55 -05:00
|
|
|
;;; Private functions
|
|
|
|
(defsubst doom--sort-alpha (it other)
|
|
|
|
(string-lessp (symbol-name (car it))
|
|
|
|
(symbol-name (car other))))
|
|
|
|
|
2017-05-19 02:57:39 +02:00
|
|
|
(defun doom--packages-choose (prompt)
|
2017-06-08 11:47:56 +02:00
|
|
|
(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))))
|
2017-05-19 02:57:39 +02:00
|
|
|
|
2017-05-19 22:29:47 +02:00
|
|
|
(defmacro doom--condition-case! (&rest body)
|
2017-06-14 12:17:36 +02:00
|
|
|
`(condition-case-unless-debug ex
|
2017-05-19 22:29:47 +02:00
|
|
|
(condition-case ex2
|
|
|
|
(progn ,@body)
|
|
|
|
('file-error
|
2017-06-14 12:17:36 +02:00
|
|
|
(message! (bold (red " FILE ERROR: %s" (error-message-string ex2))))
|
2017-05-26 10:56:55 +02:00
|
|
|
(message! " Trying again...")
|
2017-06-28 15:33:17 +02:00
|
|
|
(quiet! (doom-refresh-packages t))
|
2017-05-19 22:29:47 +02:00
|
|
|
,@body))
|
|
|
|
('user-error
|
2017-06-14 12:17:36 +02:00
|
|
|
(message! (bold (red " ERROR: (%s) %s"
|
2017-06-28 15:33:17 +02:00
|
|
|
(car ex)
|
2017-06-14 12:17:36 +02:00
|
|
|
(error-message-string ex)))))
|
2017-05-19 22:29:47 +02:00
|
|
|
('error
|
|
|
|
(doom-refresh-clear-cache)
|
2017-06-14 12:17:36 +02:00
|
|
|
(message! (bold (red " FATAL ERROR: (%s) %s"
|
2017-06-28 15:33:17 +02:00
|
|
|
(car ex)
|
2017-06-14 12:17:36 +02:00
|
|
|
(error-message-string ex)))))))
|
2017-05-19 22:29:47 +02:00
|
|
|
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
;;
|
|
|
|
;; Main functions
|
|
|
|
;;
|
|
|
|
|
2017-02-04 21:07:54 -05:00
|
|
|
(defun doom-install-package (name &optional plist)
|
2017-02-03 07:58:16 -05:00
|
|
|
"Installs package NAME with optional quelpa RECIPE (see `quelpa-recipe' for an
|
|
|
|
example; the package name can be omitted)."
|
2017-02-11 00:46:42 -05:00
|
|
|
(doom-initialize-packages)
|
2017-02-03 07:58:16 -05:00
|
|
|
(when (package-installed-p name)
|
2017-11-05 16:04:31 +01:00
|
|
|
(when (doom-package-different-backend-p name)
|
|
|
|
(doom-delete-package name t))
|
2017-06-05 14:21:52 +02:00
|
|
|
(user-error "%s is already installed" name))
|
2017-11-13 18:00:46 +01:00
|
|
|
(let* ((inhibit-message (not doom-debug-mode))
|
|
|
|
(plist (or plist (cdr (assq name doom-packages))))
|
|
|
|
(recipe (plist-get plist :recipe))
|
|
|
|
quelpa-upgrade-p)
|
|
|
|
(if recipe
|
|
|
|
(quelpa recipe)
|
|
|
|
(package-install name))
|
2017-06-08 11:47:56 +02:00
|
|
|
(when (package-installed-p name)
|
|
|
|
(cl-pushnew (cons name plist) doom-packages :test #'eq :key #'car)
|
|
|
|
t)))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-06-08 11:47:56 +02:00
|
|
|
(defun doom-update-package (name &optional force-p)
|
2017-07-02 16:47:02 +02:00
|
|
|
"Updates package NAME (a symbol) if it is out of date, using quelpa or
|
|
|
|
package.el as appropriate."
|
2017-02-03 07:58:16 -05:00
|
|
|
(unless (package-installed-p name)
|
2017-04-18 05:45:24 -04:00
|
|
|
(user-error "%s isn't installed" name))
|
2017-11-13 18:01:38 +01:00
|
|
|
(when (doom-package-different-backend-p name)
|
|
|
|
(user-error "%s's backend has changed and must be uninstalled first" name))
|
2017-06-08 11:47:56 +02:00
|
|
|
(when (or force-p (doom-package-outdated-p name))
|
2017-06-03 21:30:41 +02:00
|
|
|
(let ((inhibit-message (not doom-debug-mode))
|
|
|
|
(desc (cadr (assq name package-alist))))
|
2017-02-04 21:07:54 -05:00
|
|
|
(pcase (doom-package-backend name)
|
|
|
|
('quelpa
|
2017-06-02 22:28:46 +02:00
|
|
|
(or (quelpa-setup-p)
|
|
|
|
(error "Failed to initialize quelpa"))
|
2017-02-04 21:07:54 -05:00
|
|
|
(let ((quelpa-upgrade-p t))
|
2017-05-16 00:49:25 +02:00
|
|
|
(quelpa (assq name quelpa-cache))))
|
2017-02-04 21:07:54 -05:00
|
|
|
('elpa
|
2017-06-03 21:30:41 +02:00
|
|
|
(let* ((archive (cadr (assq name package-archive-contents)))
|
2017-06-03 21:01:32 +02:00
|
|
|
(packages
|
|
|
|
(if (package-desc-p archive)
|
|
|
|
(package-compute-transaction (list archive) (package-desc-reqs archive))
|
|
|
|
(package-compute-transaction () (list (list archive))))))
|
2017-06-05 03:15:52 +02:00
|
|
|
(package-download-transaction packages))))
|
2017-06-08 11:47:56 +02:00
|
|
|
(unless (doom-package-outdated-p name)
|
2017-12-10 14:49:52 -05:00
|
|
|
(when-let* ((old-dir (package-desc-dir desc)))
|
2017-06-08 11:47:56 +02:00
|
|
|
(when (file-directory-p old-dir)
|
|
|
|
(delete-directory old-dir t)))
|
|
|
|
t))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-05-15 22:35:57 +02:00
|
|
|
(defun doom-delete-package (name &optional force-p)
|
2017-02-03 07:58:16 -05:00
|
|
|
"Uninstalls package NAME if it exists, and clears it from `quelpa-cache'."
|
|
|
|
(unless (package-installed-p name)
|
2017-04-18 05:45:24 -04:00
|
|
|
(user-error "%s isn't installed" name))
|
2017-06-10 23:32:59 +02:00
|
|
|
(let ((inhibit-message (not doom-debug-mode))
|
|
|
|
quelpa-p)
|
2017-05-19 02:57:39 +02:00
|
|
|
(unless (quelpa-setup-p)
|
|
|
|
(error "Could not initialize QUELPA"))
|
|
|
|
(when (assq name quelpa-cache)
|
|
|
|
(setq quelpa-cache (assq-delete-all name quelpa-cache))
|
2017-06-10 23:32:59 +02:00
|
|
|
(quelpa-save-cache)
|
|
|
|
(setq quelpa-p t))
|
|
|
|
(package-delete (cadr (assq name package-alist)) force-p)
|
|
|
|
(unless (package-installed-p name)
|
|
|
|
(let ((pkg-build-dir (expand-file-name (symbol-name name) quelpa-build-dir)))
|
|
|
|
(when (and quelpa-p (file-directory-p pkg-build-dir))
|
|
|
|
(delete-directory pkg-build-dir t)))
|
|
|
|
t)))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
2017-12-22 15:25:02 -05:00
|
|
|
;; Batch/interactive commands
|
2017-02-03 07:58:16 -05:00
|
|
|
;;
|
2017-02-02 19:15:58 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-11-05 01:23:36 +01:00
|
|
|
(defun doom//packages-install ()
|
2017-02-03 19:20:47 -05:00
|
|
|
"Interactive command for installing missing packages."
|
2017-02-02 19:15:58 -05:00
|
|
|
(interactive)
|
2017-12-22 15:25:02 -05:00
|
|
|
(message! "Looking for packages to install...")
|
2017-02-11 06:01:03 -05:00
|
|
|
(let ((packages (doom-get-missing-packages)))
|
2017-02-03 07:58:16 -05:00
|
|
|
(cond ((not packages)
|
2017-04-15 01:29:24 -04:00
|
|
|
(message! (green "No packages to install!")))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-02-19 06:59:55 -05:00
|
|
|
((not (or (getenv "YES")
|
|
|
|
(y-or-n-p
|
|
|
|
(format "%s packages will be installed:\n\n%s\n\nProceed?"
|
|
|
|
(length packages)
|
2017-11-05 16:04:31 +01:00
|
|
|
(mapconcat
|
|
|
|
(lambda (pkg)
|
|
|
|
(format "+ %s (%s)"
|
|
|
|
(car pkg)
|
|
|
|
(cond ((doom-package-different-backend-p (car pkg))
|
|
|
|
(if (plist-get (cdr pkg) :recipe)
|
|
|
|
"ELPA -> QUELPA"
|
|
|
|
"QUELPA -> ELPA"))
|
|
|
|
((plist-get (cdr pkg) :recipe)
|
|
|
|
"QUELPA")
|
|
|
|
(t
|
|
|
|
"ELPA"))))
|
|
|
|
(sort (cl-copy-list packages) #'doom--sort-alpha)
|
|
|
|
"\n")))))
|
2017-04-15 01:29:24 -04:00
|
|
|
(message! (yellow "Aborted!")))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
(t
|
2017-05-27 18:29:32 +02:00
|
|
|
(doom-refresh-packages doom-debug-mode)
|
2017-02-03 07:58:16 -05:00
|
|
|
(dolist (pkg packages)
|
2017-05-19 02:57:39 +02:00
|
|
|
(message! "Installing %s" (car pkg))
|
2017-05-19 22:29:47 +02:00
|
|
|
(doom--condition-case!
|
2017-12-20 20:07:46 -05:00
|
|
|
(message! "%s%s"
|
2017-11-13 18:02:57 +01:00
|
|
|
(cond ((and (package-installed-p (car pkg))
|
|
|
|
(not (doom-package-different-backend-p (car pkg))))
|
2017-12-20 20:07:46 -05:00
|
|
|
(dark (white "⚠ ALREADY INSTALLED")))
|
2017-05-19 22:29:47 +02:00
|
|
|
((doom-install-package (car pkg) (cdr pkg))
|
2017-12-20 20:07:46 -05:00
|
|
|
(green "✓ DONE"))
|
2017-05-19 22:29:47 +02:00
|
|
|
(t
|
2017-12-20 20:07:46 -05:00
|
|
|
(red "✕ FAILED")))
|
2017-05-19 22:29:47 +02:00
|
|
|
(if (plist-member (cdr pkg) :pin)
|
|
|
|
(format " [pinned: %s]" (plist-get (cdr pkg) :pin))
|
2017-12-20 20:10:14 -05:00
|
|
|
""))))
|
2017-04-12 08:53:54 -04:00
|
|
|
|
2017-12-20 20:10:14 -05:00
|
|
|
(message! (bold (green "Finished!")))
|
|
|
|
(doom//reload-load-path)))))
|
2017-02-02 19:15:58 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-11-05 01:23:36 +01:00
|
|
|
(defun doom//packages-update ()
|
2017-02-03 19:20:47 -05:00
|
|
|
"Interactive command for updating packages."
|
2017-02-02 19:15:58 -05:00
|
|
|
(interactive)
|
2017-05-27 18:29:32 +02:00
|
|
|
(doom-refresh-packages doom-debug-mode)
|
2017-06-03 21:31:16 +02:00
|
|
|
(message! "Looking for outdated packages...")
|
2017-04-17 02:17:10 -04:00
|
|
|
(let ((packages (sort (doom-get-outdated-packages) #'doom--sort-alpha)))
|
2017-02-03 07:58:16 -05:00
|
|
|
(cond ((not packages)
|
2017-04-15 01:29:24 -04:00
|
|
|
(message! (green "Everything is up-to-date")))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
2017-02-19 06:59:55 -05:00
|
|
|
((not (or (getenv "YES")
|
|
|
|
(y-or-n-p
|
|
|
|
(format "%s packages will be updated:\n\n%s\n\nProceed?"
|
|
|
|
(length packages)
|
|
|
|
(let ((max-len
|
|
|
|
(or (car (sort (mapcar (lambda (it) (length (symbol-name (car it)))) packages)
|
|
|
|
(lambda (it other) (> it other))))
|
|
|
|
10)))
|
|
|
|
(mapconcat
|
|
|
|
(lambda (pkg)
|
2017-06-24 02:10:40 +02:00
|
|
|
(format (format "+ %%-%ds %%-%ds -> %%s" (+ max-len 2) 14)
|
|
|
|
(symbol-name (car pkg))
|
|
|
|
(package-version-join (cadr pkg))
|
2017-04-04 13:16:11 -04:00
|
|
|
(package-version-join (cl-caddr pkg))))
|
2017-02-19 06:59:55 -05:00
|
|
|
packages
|
|
|
|
"\n"))))))
|
2017-04-15 01:29:24 -04:00
|
|
|
(message! (yellow "Aborted!")))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
(t
|
|
|
|
(dolist (pkg packages)
|
2017-05-19 02:57:39 +02:00
|
|
|
(message! "Updating %s" (car pkg))
|
2017-05-19 22:29:47 +02:00
|
|
|
(doom--condition-case!
|
|
|
|
(message!
|
2017-06-08 11:47:56 +02:00
|
|
|
(let ((result (doom-update-package (car pkg) t)))
|
2017-05-19 22:29:47 +02:00
|
|
|
(color (if result 'green 'red)
|
2017-12-20 20:07:46 -05:00
|
|
|
(if result "✓ DONE" "✕ FAILED"))))))
|
2017-04-12 08:53:54 -04:00
|
|
|
|
2017-04-16 11:54:22 -04:00
|
|
|
(message! (bold (green "Finished!")))
|
2017-11-05 01:23:36 +01:00
|
|
|
(doom//reload-load-path)))))
|
2017-02-02 19:15:58 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-11-05 01:23:36 +01:00
|
|
|
(defun doom//packages-autoremove ()
|
2017-02-03 19:20:47 -05:00
|
|
|
"Interactive command for auto-removing orphaned packages."
|
2017-02-02 19:15:58 -05:00
|
|
|
(interactive)
|
2017-12-22 15:25:02 -05:00
|
|
|
(message! "Looking for orphaned packages...")
|
2017-02-03 07:58:16 -05:00
|
|
|
(let ((packages (doom-get-orphaned-packages)))
|
|
|
|
(cond ((not packages)
|
2017-04-15 01:29:24 -04:00
|
|
|
(message! (green "No unused packages to remove")))
|
2017-02-02 19:15:58 -05:00
|
|
|
|
2017-12-22 15:25:02 -05:00
|
|
|
((not
|
|
|
|
(or (getenv "YES")
|
|
|
|
(y-or-n-p
|
|
|
|
(format
|
|
|
|
"%s packages will be deleted:\n\n%s\n\nProceed?"
|
|
|
|
(length packages)
|
|
|
|
(mapconcat
|
|
|
|
(lambda (sym)
|
|
|
|
(format "+ %s (%s)" sym
|
|
|
|
(let ((backend (doom-package-backend sym)))
|
|
|
|
(if (doom-package-different-backend-p sym)
|
|
|
|
(if (eq backend 'quelpa)
|
|
|
|
"QUELPA->ELPA"
|
|
|
|
"ELPA->QUELPA")
|
|
|
|
(upcase (symbol-name backend))))))
|
|
|
|
(sort (cl-copy-list packages) #'string-lessp)
|
|
|
|
"\n")))))
|
2017-04-15 01:29:24 -04:00
|
|
|
(message! (yellow "Aborted!")))
|
2017-02-02 19:15:58 -05:00
|
|
|
|
|
|
|
(t
|
2017-02-03 07:58:16 -05:00
|
|
|
(dolist (pkg packages)
|
2017-05-19 22:29:47 +02:00
|
|
|
(doom--condition-case!
|
|
|
|
(message!
|
|
|
|
(let ((result (doom-delete-package pkg t)))
|
|
|
|
(color (if result 'green 'red)
|
|
|
|
"%s %s"
|
2017-12-20 20:07:46 -05:00
|
|
|
(if result "✓ Removed" "✕ Failed to remove")
|
2017-05-19 22:29:47 +02:00
|
|
|
pkg)))))
|
2017-04-12 08:53:54 -04:00
|
|
|
|
2017-04-16 11:54:22 -04:00
|
|
|
(message! (bold (green "Finished!")))
|
2017-11-05 01:23:36 +01:00
|
|
|
(doom//reload-load-path)))))
|
2017-02-11 00:46:42 -05:00
|
|
|
|
2017-11-05 16:04:31 +01:00
|
|
|
|
2017-12-22 15:25:02 -05:00
|
|
|
;;
|
|
|
|
;; Interactive commands
|
|
|
|
;;
|
|
|
|
|
2017-02-02 19:15:58 -05:00
|
|
|
;;;###autoload
|
2017-04-17 02:17:10 -04:00
|
|
|
(defalias 'doom/install-package #'package-install)
|
2017-02-02 19:15:58 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-05-19 02:57:39 +02:00
|
|
|
(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)
|
2017-02-11 00:46:42 -05:00
|
|
|
"Prompts the user with a list of packages and deletes the selected package.
|
|
|
|
Use this interactively. Use `doom-delete-package' for direct calls."
|
2017-04-17 16:54:31 -04:00
|
|
|
(declare (interactive-only t))
|
2017-02-03 07:58:16 -05:00
|
|
|
(interactive
|
2017-05-19 02:57:39 +02:00
|
|
|
(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"
|
2017-12-22 15:25:02 -05:00
|
|
|
(if (doom-delete-package package t)
|
|
|
|
"Deleted"
|
|
|
|
"Failed to delete")
|
2017-05-19 02:57:39 +02:00
|
|
|
package)
|
|
|
|
(message "Aborted"))
|
|
|
|
(message "%s isn't installed" package))))
|
2017-02-03 07:58:16 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2017-05-19 02:57:39 +02:00
|
|
|
(defun doom/update-package (pkg)
|
2017-02-11 00:46:42 -05:00
|
|
|
"Prompts the user with a list of outdated packages and updates the selected
|
|
|
|
package. Use this interactively. Use `doom-update-package' for direct
|
|
|
|
calls."
|
2017-02-06 00:13:24 -05:00
|
|
|
(declare (interactive-only t))
|
2017-02-03 07:58:16 -05:00
|
|
|
(interactive
|
2017-05-19 02:57:39 +02:00
|
|
|
(let* ((packages (doom-get-outdated-packages))
|
|
|
|
(package (if packages
|
|
|
|
(completing-read "Update package: "
|
|
|
|
(mapcar #'car packages)
|
|
|
|
nil t)
|
|
|
|
(user-error "All packages are up to date"))))
|
|
|
|
(list (cdr (assq (car (assoc package package-alist)) packages)))))
|
2017-06-25 02:04:50 +02:00
|
|
|
(cl-destructuring-bind (package old-version new-version) pkg
|
2017-12-10 14:49:52 -05:00
|
|
|
(if-let* ((desc (doom-package-outdated-p package)))
|
2017-05-19 02:57:39 +02:00
|
|
|
(let ((old-v-str (package-version-join old-version))
|
|
|
|
(new-v-str (package-version-join new-version)))
|
|
|
|
(if (y-or-n-p (format "%s will be updated from %s to %s. Update?"
|
|
|
|
package old-v-str new-v-str))
|
|
|
|
(message "%s %s (%s => %s)"
|
2017-06-08 11:47:56 +02:00
|
|
|
(if (doom-update-package package t) "Updated" "Failed to update")
|
2017-05-19 02:57:39 +02:00
|
|
|
package old-v-str new-v-str)
|
|
|
|
(message "Aborted")))
|
|
|
|
(message "%s is up-to-date" package))))
|
2017-05-19 22:28:01 +02:00
|
|
|
|
2017-05-19 22:29:47 +02:00
|
|
|
;;;###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")
|
2017-05-26 11:17:19 +02:00
|
|
|
(doom-refresh-packages force-p))
|