]> git.eshelyaron.com Git - emacs.git/commitdiff
emacs-lisp/package.el (package-menu-execute): Add async support
authorArtur Malabarba <bruce.connor.am@gmail.com>
Sun, 5 Apr 2015 22:39:43 +0000 (23:39 +0100)
committerArtur Malabarba <bruce.connor.am@gmail.com>
Mon, 6 Apr 2015 10:19:04 +0000 (11:19 +0100)
Most install/delete logic is now in
`package-menu--perform-transaction', and this function is called
asynchronously if `package-menu-async' is non-nil.

lisp/ChangeLog
lisp/emacs-lisp/package.el

index 07e9542937512199dd50ff1c5429f5eb20455059..2fa005484a892ea5ffef612a8867dd5a1a7d4b06 100644 (file)
@@ -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)
 
index 6d5d46c14bbba7038f25d68737b2c4c55586a6fd..acfab92e7eb0975214073ee48b02555e7391ae97 100644 (file)
@@ -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")
@@ -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;
@@ -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)))
@@ -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)
@@ -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)