diff options
| author | Chong Yidong | 2011-09-14 21:57:54 -0400 |
|---|---|---|
| committer | Chong Yidong | 2011-09-14 21:57:54 -0400 |
| commit | 25322144fc19c9e3dd04a6530e9dcdddffd7bccb (patch) | |
| tree | 49e20a773d1b5282b78fdeeeda3de972f16fc413 | |
| parent | d5fdf93f872b2ced7e1e41cee44677c71cac8b26 (diff) | |
| download | emacs-25322144fc19c9e3dd04a6530e9dcdddffd7bccb.tar.gz emacs-25322144fc19c9e3dd04a6530e9dcdddffd7bccb.zip | |
Add an "mark upgradable packages" command to Package Menu mode.
* lisp/emacs-lisp/package.el (package-alist): Fix risky-local-variable
declaration.
(package--add-to-archive-contents): If there is a duplicate entry
with an older version, remove it.
(package-menu-mark-delete, package-menu-mark-install)
(package-menu-mark-unmark): Make unused args optional.
(package-menu-mark-obsolete-for-deletion): Use
package-menu-get-status instead of a regexp search.
(package-menu-get-status): Use tabulated-list-entry.
(package-menu-mark-upgrades): New command.
(package-menu-mode-map): Bind it to U.
(package-menu-execute): Do installation before deletion.
(package-menu-refresh, package-menu-execute): Use derived-mode-p
instead of checking major-mode.
(package-menu--find-upgrades): New function.
| -rw-r--r-- | lisp/ChangeLog | 18 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package.el | 113 |
2 files changed, 105 insertions, 26 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 3d71b646b7a..9c37f630d72 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,21 @@ | |||
| 1 | 2011-09-15 Chong Yidong <cyd@stupidchicken.com> | ||
| 2 | |||
| 3 | * emacs-lisp/package.el (package-alist): Fix risky-local-variable | ||
| 4 | declaration. | ||
| 5 | (package--add-to-archive-contents): If there is a duplicate entry | ||
| 6 | with an older version, remove it. | ||
| 7 | (package-menu-mark-delete, package-menu-mark-install) | ||
| 8 | (package-menu-mark-unmark): Make unused args optional. | ||
| 9 | (package-menu-mark-obsolete-for-deletion): Use | ||
| 10 | package-menu-get-status instead of a regexp search. | ||
| 11 | (package-menu-get-status): Use tabulated-list-entry. | ||
| 12 | (package-menu-mark-upgrades): New command. | ||
| 13 | (package-menu-mode-map): Bind it to U. | ||
| 14 | (package-menu-execute): Do installation before deletion. | ||
| 15 | (package-menu-refresh, package-menu-execute): Use derived-mode-p | ||
| 16 | instead of checking major-mode. | ||
| 17 | (package-menu--find-upgrades): New function. | ||
| 18 | |||
| 1 | 2011-09-14 Lars Magne Ingebrigtsen <larsi@gnus.org> | 19 | 2011-09-14 Lars Magne Ingebrigtsen <larsi@gnus.org> |
| 2 | 20 | ||
| 3 | * mail/smtpmail.el (smtpmail-send-command): Don't include AUTH | 21 | * mail/smtpmail.el (smtpmail-send-command): Don't include AUTH |
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index caf0ec2e8b8..92223b33733 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el | |||
| @@ -309,7 +309,7 @@ The vector DESC has the form [VERSION-LIST REQS DOCSTRING]. | |||
| 309 | This variable is set automatically by `package-load-descriptor', | 309 | This variable is set automatically by `package-load-descriptor', |
| 310 | called via `package-initialize'. To change which packages are | 310 | called via `package-initialize'. To change which packages are |
| 311 | loaded and/or activated, customize `package-load-list'.") | 311 | loaded and/or activated, customize `package-load-list'.") |
| 312 | (put 'package-archive-contents 'risky-local-variable t) | 312 | (put 'package-alist 'risky-local-variable t) |
| 313 | 313 | ||
| 314 | (defvar package-activated-list nil | 314 | (defvar package-activated-list nil |
| 315 | "List of the names of currently activated packages.") | 315 | "List of the names of currently activated packages.") |
| @@ -820,13 +820,19 @@ If the archive version is too new, signal an error." | |||
| 820 | "Add the PACKAGE from the given ARCHIVE if necessary. | 820 | "Add the PACKAGE from the given ARCHIVE if necessary. |
| 821 | Also, add the originating archive to the end of the package vector." | 821 | Also, add the originating archive to the end of the package vector." |
| 822 | (let* ((name (car package)) | 822 | (let* ((name (car package)) |
| 823 | (version (aref (cdr package) 0)) | 823 | (version (package-desc-vers (cdr package))) |
| 824 | (entry (cons (car package) | 824 | (entry (cons name |
| 825 | (vconcat (cdr package) (vector archive)))) | 825 | (vconcat (cdr package) (vector archive)))) |
| 826 | (existing-package (cdr (assq name package-archive-contents)))) | 826 | (existing-package (assq name package-archive-contents))) |
| 827 | (when (or (not existing-package) | 827 | (cond ((not existing-package) |
| 828 | (version-list-< (aref existing-package 0) version)) | 828 | (add-to-list 'package-archive-contents entry)) |
| 829 | (add-to-list 'package-archive-contents entry)))) | 829 | ((version-list-< (package-desc-vers (cdr existing-package)) |
| 830 | version) | ||
| 831 | ;; Replace the entry with this one. | ||
| 832 | (setq package-archive-contents | ||
| 833 | (cons entry | ||
| 834 | (delq existing-package | ||
| 835 | package-archive-contents))))))) | ||
| 830 | 836 | ||
| 831 | (defun package-download-transaction (package-list) | 837 | (defun package-download-transaction (package-list) |
| 832 | "Download and install all the packages in PACKAGE-LIST. | 838 | "Download and install all the packages in PACKAGE-LIST. |
| @@ -1269,6 +1275,7 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages." | |||
| 1269 | (define-key map "\177" 'package-menu-backup-unmark) | 1275 | (define-key map "\177" 'package-menu-backup-unmark) |
| 1270 | (define-key map "d" 'package-menu-mark-delete) | 1276 | (define-key map "d" 'package-menu-mark-delete) |
| 1271 | (define-key map "i" 'package-menu-mark-install) | 1277 | (define-key map "i" 'package-menu-mark-install) |
| 1278 | (define-key map "U" 'package-menu-mark-upgrades) | ||
| 1272 | (define-key map "r" 'package-menu-refresh) | 1279 | (define-key map "r" 'package-menu-refresh) |
| 1273 | (define-key map "~" 'package-menu-mark-obsolete-for-deletion) | 1280 | (define-key map "~" 'package-menu-mark-obsolete-for-deletion) |
| 1274 | (define-key map "x" 'package-menu-execute) | 1281 | (define-key map "x" 'package-menu-execute) |
| @@ -1422,7 +1429,7 @@ identifier (NAME . VERSION-LIST)." | |||
| 1422 | This fetches the contents of each archive specified in | 1429 | This fetches the contents of each archive specified in |
| 1423 | `package-archives', and then refreshes the package menu." | 1430 | `package-archives', and then refreshes the package menu." |
| 1424 | (interactive) | 1431 | (interactive) |
| 1425 | (unless (eq major-mode 'package-menu-mode) | 1432 | (unless (derived-mode-p 'package-menu-mode) |
| 1426 | (error "The current buffer is not a Package Menu")) | 1433 | (error "The current buffer is not a Package Menu")) |
| 1427 | (package-refresh-contents) | 1434 | (package-refresh-contents) |
| 1428 | (package-menu--generate t t)) | 1435 | (package-menu--generate t t)) |
| @@ -1437,21 +1444,21 @@ If optional arg BUTTON is non-nil, describe its associated package." | |||
| 1437 | (describe-package package)))) | 1444 | (describe-package package)))) |
| 1438 | 1445 | ||
| 1439 | ;; fixme numeric argument | 1446 | ;; fixme numeric argument |
| 1440 | (defun package-menu-mark-delete (num) | 1447 | (defun package-menu-mark-delete (&optional num) |
| 1441 | "Mark a package for deletion and move to the next line." | 1448 | "Mark a package for deletion and move to the next line." |
| 1442 | (interactive "p") | 1449 | (interactive "p") |
| 1443 | (if (member (package-menu-get-status) '("installed" "obsolete")) | 1450 | (if (member (package-menu-get-status) '("installed" "obsolete")) |
| 1444 | (tabulated-list-put-tag "D" t) | 1451 | (tabulated-list-put-tag "D" t) |
| 1445 | (forward-line))) | 1452 | (forward-line))) |
| 1446 | 1453 | ||
| 1447 | (defun package-menu-mark-install (num) | 1454 | (defun package-menu-mark-install (&optional num) |
| 1448 | "Mark a package for installation and move to the next line." | 1455 | "Mark a package for installation and move to the next line." |
| 1449 | (interactive "p") | 1456 | (interactive "p") |
| 1450 | (if (string-equal (package-menu-get-status) "available") | 1457 | (if (string-equal (package-menu-get-status) "available") |
| 1451 | (tabulated-list-put-tag "I" t) | 1458 | (tabulated-list-put-tag "I" t) |
| 1452 | (forward-line))) | 1459 | (forward-line))) |
| 1453 | 1460 | ||
| 1454 | (defun package-menu-mark-unmark (num) | 1461 | (defun package-menu-mark-unmark (&optional num) |
| 1455 | "Clear any marks on a package and move to the next line." | 1462 | "Clear any marks on a package and move to the next line." |
| 1456 | (interactive "p") | 1463 | (interactive "p") |
| 1457 | (tabulated-list-put-tag " " t)) | 1464 | (tabulated-list-put-tag " " t)) |
| @@ -1467,9 +1474,8 @@ If optional arg BUTTON is non-nil, describe its associated package." | |||
| 1467 | (interactive) | 1474 | (interactive) |
| 1468 | (save-excursion | 1475 | (save-excursion |
| 1469 | (goto-char (point-min)) | 1476 | (goto-char (point-min)) |
| 1470 | (forward-line 2) | ||
| 1471 | (while (not (eobp)) | 1477 | (while (not (eobp)) |
| 1472 | (if (looking-at ".*\\s obsolete\\s ") | 1478 | (if (equal (package-menu-get-status) "obsolete") |
| 1473 | (tabulated-list-put-tag "D" t) | 1479 | (tabulated-list-put-tag "D" t) |
| 1474 | (forward-line 1))))) | 1480 | (forward-line 1))))) |
| 1475 | 1481 | ||
| @@ -1482,17 +1488,66 @@ If optional arg BUTTON is non-nil, describe its associated package." | |||
| 1482 | 'package-menu-view-commentary 'package-menu-describe-package "24.1") | 1488 | 'package-menu-view-commentary 'package-menu-describe-package "24.1") |
| 1483 | 1489 | ||
| 1484 | (defun package-menu-get-status () | 1490 | (defun package-menu-get-status () |
| 1485 | (save-excursion | 1491 | (let* ((pkg (tabulated-list-get-id)) |
| 1486 | (if (looking-at ". [^ \t]*[ \t]*[^ \t]*[ \t]*\\([^ \t]*\\)") | 1492 | (entry (and pkg (assq pkg tabulated-list-entries)))) |
| 1487 | (match-string 1) | 1493 | (if entry |
| 1494 | (aref (cadr entry) 2) | ||
| 1488 | ""))) | 1495 | ""))) |
| 1489 | 1496 | ||
| 1497 | (defun package-menu--find-upgrades () | ||
| 1498 | (let (installed available upgrades) | ||
| 1499 | ;; Build list of installed/available packages in this buffer. | ||
| 1500 | (dolist (entry tabulated-list-entries) | ||
| 1501 | ;; ENTRY is ((NAME . VERSION) [NAME VERSION STATUS DOC]) | ||
| 1502 | (let ((pkg (car entry)) | ||
| 1503 | (status (aref (cadr entry) 2)) | ||
| 1504 | old) | ||
| 1505 | (cond ((equal status "installed") | ||
| 1506 | (push pkg installed)) | ||
| 1507 | ((equal status "available") | ||
| 1508 | (push pkg available))))) | ||
| 1509 | ;; Loop through list of installed packages, finding upgrades | ||
| 1510 | (dolist (pkg installed) | ||
| 1511 | (let ((avail-pkg (assq (car pkg) available))) | ||
| 1512 | (and avail-pkg | ||
| 1513 | (version-list-< (cdr pkg) (cdr avail-pkg)) | ||
| 1514 | (push avail-pkg upgrades)))) | ||
| 1515 | upgrades)) | ||
| 1516 | |||
| 1517 | (defun package-menu-mark-upgrades () | ||
| 1518 | "Mark all upgradable packages in the Package Menu. | ||
| 1519 | For each installed package with a newer version available, place | ||
| 1520 | an (I)nstall flag on the available version and a (D)elete flag on | ||
| 1521 | the installed version. A subsequent \\[package-menu-execute] | ||
| 1522 | call will upgrade the package." | ||
| 1523 | (interactive) | ||
| 1524 | (unless (derived-mode-p 'package-menu-mode) | ||
| 1525 | (error "The current buffer is not a Package Menu")) | ||
| 1526 | (let ((upgrades (package-menu--find-upgrades))) | ||
| 1527 | (if (null upgrades) | ||
| 1528 | (message "No packages to upgrade.") | ||
| 1529 | (widen) | ||
| 1530 | (save-excursion | ||
| 1531 | (goto-char (point-min)) | ||
| 1532 | (while (not (eobp)) | ||
| 1533 | (let* ((pkg (tabulated-list-get-id)) | ||
| 1534 | (upgrade (assq (car pkg) upgrades))) | ||
| 1535 | (cond ((null upgrade) | ||
| 1536 | (forward-line 1)) | ||
| 1537 | ((equal pkg upgrade) | ||
| 1538 | (package-menu-mark-install)) | ||
| 1539 | (t | ||
| 1540 | (package-menu-mark-delete)))))) | ||
| 1541 | (message "%d package%s marked for upgrading." | ||
| 1542 | (length upgrades) | ||
| 1543 | (if (= (length upgrades) 1) "" "s"))))) | ||
| 1544 | |||
| 1490 | (defun package-menu-execute () | 1545 | (defun package-menu-execute () |
| 1491 | "Perform marked Package Menu actions. | 1546 | "Perform marked Package Menu actions. |
| 1492 | Packages marked for installation are downloaded and installed; | 1547 | Packages marked for installation are downloaded and installed; |
| 1493 | packages marked for deletion are removed." | 1548 | packages marked for deletion are removed." |
| 1494 | (interactive) | 1549 | (interactive) |
| 1495 | (unless (eq major-mode 'package-menu-mode) | 1550 | (unless (derived-mode-p 'package-menu-mode) |
| 1496 | (error "The current buffer is not in Package Menu mode")) | 1551 | (error "The current buffer is not in Package Menu mode")) |
| 1497 | (let (install-list delete-list cmd id) | 1552 | (let (install-list delete-list cmd id) |
| 1498 | (save-excursion | 1553 | (save-excursion |
| @@ -1509,6 +1564,14 @@ packages marked for deletion are removed." | |||
| 1509 | ((eq cmd ?I) | 1564 | ((eq cmd ?I) |
| 1510 | (push (car id) install-list)))) | 1565 | (push (car id) install-list)))) |
| 1511 | (forward-line))) | 1566 | (forward-line))) |
| 1567 | (when install-list | ||
| 1568 | (if (yes-or-no-p | ||
| 1569 | (if (= (length install-list) 1) | ||
| 1570 | (format "Install package `%s'? " (car install-list)) | ||
| 1571 | (format "Install these %d packages (%s)? " | ||
| 1572 | (length install-list) | ||
| 1573 | (mapconcat 'symbol-name install-list ", ")))) | ||
| 1574 | (mapc 'package-install install-list))) | ||
| 1512 | ;; Delete packages, prompting if necessary. | 1575 | ;; Delete packages, prompting if necessary. |
| 1513 | (when delete-list | 1576 | (when delete-list |
| 1514 | (if (yes-or-no-p | 1577 | (if (yes-or-no-p |
| @@ -1527,14 +1590,6 @@ packages marked for deletion are removed." | |||
| 1527 | (package-delete (car elt) (cdr elt)) | 1590 | (package-delete (car elt) (cdr elt)) |
| 1528 | (error (message (cadr err))))) | 1591 | (error (message (cadr err))))) |
| 1529 | (error "Aborted"))) | 1592 | (error "Aborted"))) |
| 1530 | (when install-list | ||
| 1531 | (if (yes-or-no-p | ||
| 1532 | (if (= (length install-list) 1) | ||
| 1533 | (format "Install package `%s'? " (car install-list)) | ||
| 1534 | (format "Install these %d packages (%s)? " | ||
| 1535 | (length install-list) | ||
| 1536 | (mapconcat 'symbol-name install-list ", ")))) | ||
| 1537 | (mapc 'package-install install-list))) | ||
| 1538 | ;; If we deleted anything, regenerate `package-alist'. This is done | 1593 | ;; If we deleted anything, regenerate `package-alist'. This is done |
| 1539 | ;; automatically if we installed a package. | 1594 | ;; automatically if we installed a package. |
| 1540 | (and delete-list (null install-list) | 1595 | (and delete-list (null install-list) |
| @@ -1597,7 +1652,13 @@ The list is displayed in a buffer named `*Packages*'." | |||
| 1597 | (package-menu--generate nil t)) | 1652 | (package-menu--generate nil t)) |
| 1598 | ;; The package menu buffer has keybindings. If the user types | 1653 | ;; The package menu buffer has keybindings. If the user types |
| 1599 | ;; `M-x list-packages', that suggests it should become current. | 1654 | ;; `M-x list-packages', that suggests it should become current. |
| 1600 | (switch-to-buffer buf))) | 1655 | (switch-to-buffer buf)) |
| 1656 | (let ((upgrades (package-menu--find-upgrades))) | ||
| 1657 | (if upgrades | ||
| 1658 | (message "%d package%s can be upgraded; type `%s' to mark them for upgrading." | ||
| 1659 | (length upgrades) | ||
| 1660 | (if (= (length upgrades) 1) "" "s") | ||
| 1661 | (substitute-command-keys "\\[package-menu-mark-upgrades]"))))) | ||
| 1601 | 1662 | ||
| 1602 | ;;;###autoload | 1663 | ;;;###autoload |
| 1603 | (defalias 'package-list-packages 'list-packages) | 1664 | (defalias 'package-list-packages 'list-packages) |