Skip to content

Commit

Permalink
emacs-lisp/package.el (package-menu-execute): Add async support
Browse files Browse the repository at this point in the history
Most install/delete logic is now in
`package-menu--perform-transaction', and this function is called
asynchronously if `package-menu-async' is non-nil.
  • Loading branch information
Malabarba committed Apr 6, 2015
1 parent 6701726 commit 7471fc4
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 29 deletions.
2 changes: 2 additions & 0 deletions lisp/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
(package-menu-execute): Use it to prompt the user about operations
to be executed.
(package-install): Add ASYNC and CALLBACK arguments.
(package-menu--perform-transaction): New function.
(package-menu-execute): Use it to install and delete packages.

2015-04-05 Pete Williamson <petewil@chromium.org> (tiny-change)

Expand Down
67 changes: 38 additions & 29 deletions lisp/emacs-lisp/package.el
Original file line number Diff line number Diff line change
Expand Up @@ -1368,8 +1368,8 @@ Once it's empty, run `package--post-download-archives-hook'."
(remove entry package--downloads-in-progress))
;; If this was the last download, run the hook.
(unless package--downloads-in-progress
(package--build-compatibility-table)
(package-read-all-archive-contents)
(package--build-compatibility-table)
;; We message before running the hook, so the hook can give
;; messages as well.
(message "Package refresh done")
Expand Down Expand Up @@ -2724,6 +2724,36 @@ not both."
(mapconcat #'package-desc-full-name del ", ")))))
"? ")))

(defun package-menu--perform-transaction (install-list delete-list &optional async)
"Install packages in INSTALL-LIST and delete DELETE-LIST.
If ASYNC is non-nil, perform the installation downloads
asynchronously."
;; While there are packages to install, call `package-install' on
;; the next one and defer deletion to the callback function.
(if install-list
(let* ((pkg (car install-list))
(rest (cdr install-list))
;; Don't mark as selected if it's a new version of an
;; installed package.
(dont-mark (and (not (package-installed-p pkg))
(package-installed-p
(package-desc-name pkg)))))
(package-install
pkg dont-mark async
(lambda () (package-menu--perform-transaction rest delete-list async))))
;; Once there are no more packages to install, proceed to
;; deletion.
(dolist (elt (package--sort-by-dependence delete-list))
(condition-case-unless-debug err
(package-delete elt)
(error (message (cadr err)))))
(when package-selected-packages
(when-let ((removable (package--removable-packages)))
(message "These %d packages are no longer needed, type `M-x package-autoremove' to remove them (%s)"
(length removable)
(mapconcat #'symbol-name removable ", "))))
(package-menu--post-refresh)))

(defun package-menu-execute (&optional noquery)
"Perform marked Package Menu actions.
Packages marked for installation are downloaded and installed;
Expand All @@ -2749,28 +2779,9 @@ Optional argument NOQUERY non-nil means do not ask the user to confirm."
(user-error "No operations specified"))
(when (or noquery
(package-menu--prompt-transaction-p install-list delete-list))
;; Don't mark as selected if it's a new version of an installed
;; package.
(mapc (lambda (p) (package-install p (and (not (package-installed-p p))
(package-installed-p
(package-desc-name p)))))
install-list)
;; Delete packages.
(dolist (elt (package--sort-by-dependence delete-list))
(condition-case-unless-debug err
(package-delete elt)
(error (message (cadr err)))))
(when package-selected-packages
(let ((removable (package--removable-packages)))
(when (and removable
(y-or-n-p
(format "These %d packages are no longer needed, delete them (%s)? "
(length removable)
(mapconcat #'symbol-name removable ", "))))
;; We know these are removable, so we can use force instead of sorting them.
(mapc (lambda (p) (package-delete (cadr (assq p package-alist)) 'force 'nosave))
removable)))))
(package-menu--generate t t)))
;; This calls `package-menu--generate' after everything's done.
(package-menu--perform-transaction
install-list delete-list package-menu-async))))

(defun package-menu--version-predicate (A B)
(let ((vA (or (aref (cadr A) 1) '(0)))
Expand Down Expand Up @@ -2843,9 +2854,8 @@ Store this list in `package-menu--new-package-list'."

(defun package-menu--post-refresh ()
"Check for new packages, revert the *Packages* buffer, and check for upgrades.
This function is called after `package-refresh-contents' is done.
It goes in `package--post-download-archives-hook', so that it
works with async refresh as well."
This function is called after `package-refresh-contents' and
after `package-menu--perform-transaction'."
(package-menu--populate-new-package-list)
(let ((buf (get-buffer "*Packages*")))
(when (buffer-live-p buf)
Expand All @@ -2855,9 +2865,8 @@ works with async refresh as well."

(defcustom package-menu-async t
"If non-nil, package-menu will use async operations when possible.
Currently, only the refreshing of archive contents supports
asynchronous operations. Package transactions are still done
synchronously."
This includes refreshing archive contents as well as installing
packages."
:type 'boolean
:group 'package)

Expand Down

0 comments on commit 7471fc4

Please sign in to comment.