+(defun package-menu--find-upgrades ()
+ (let (installed available upgrades)
+ ;; Build list of installed/available packages in this buffer.
+ (dolist (entry tabulated-list-entries)
+ ;; ENTRY is ((NAME . VERSION) [NAME VERSION STATUS DOC])
+ (let ((pkg (car entry))
+ (status (aref (cadr entry) 2)))
+ (cond ((equal status "installed")
+ (push pkg installed))
+ ((equal status "available")
+ (push pkg available)))))
+ ;; Loop through list of installed packages, finding upgrades
+ (dolist (pkg installed)
+ (let ((avail-pkg (assq (car pkg) available)))
+ (and avail-pkg
+ (version-list-< (cdr pkg) (cdr avail-pkg))
+ (push avail-pkg upgrades))))
+ upgrades))
+
+(defun package-menu-mark-upgrades ()
+ "Mark all upgradable packages in the Package Menu.
+For each installed package with a newer version available, place
+an (I)nstall flag on the available version and a (D)elete flag on
+the installed version. A subsequent \\[package-menu-execute]
+call will upgrade the package."
+ (interactive)
+ (unless (derived-mode-p 'package-menu-mode)
+ (error "The current buffer is not a Package Menu"))
+ (let ((upgrades (package-menu--find-upgrades)))
+ (if (null upgrades)
+ (message "No packages to upgrade.")
+ (widen)
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (let* ((pkg (tabulated-list-get-id))
+ (upgrade (assq (car pkg) upgrades)))
+ (cond ((null upgrade)
+ (forward-line 1))
+ ((equal pkg upgrade)
+ (package-menu-mark-install))
+ (t
+ (package-menu-mark-delete))))))
+ (message "%d package%s marked for upgrading."
+ (length upgrades)
+ (if (= (length upgrades) 1) "" "s")))))
+