diff options
| -rw-r--r-- | doc/emacs/package.texi | 11 | ||||
| -rw-r--r-- | etc/NEWS | 8 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package.el | 310 |
3 files changed, 272 insertions, 57 deletions
diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi index 2de3d25e7f9..e6432678c62 100644 --- a/doc/emacs/package.texi +++ b/doc/emacs/package.texi | |||
| @@ -402,6 +402,17 @@ package is somehow unavailable, Emacs signals an error and stops | |||
| 402 | installation.) A package's requirements list is shown in its help | 402 | installation.) A package's requirements list is shown in its help |
| 403 | buffer. | 403 | buffer. |
| 404 | 404 | ||
| 405 | @cindex review | ||
| 406 | @vindex package-review-policy | ||
| 407 | If you are cautious when it comes to installing and upgrading packages | ||
| 408 | from package archives, you can configure @code{package-review-policy} to | ||
| 409 | give you a chance to review packages before installing them. By setting | ||
| 410 | the user option to @code{t}, you get to review all packages (including | ||
| 411 | dependencies), during which you can browse the source code, examine a | ||
| 412 | diff between the downloaded package and a previous installation or read | ||
| 413 | a changelog. You can also configure @code{package-review-policy} to | ||
| 414 | selectively trust or distrust specific packages or archives. | ||
| 415 | |||
| 405 | @cindex GNU ELPA | 416 | @cindex GNU ELPA |
| 406 | @cindex NonGNU ELPA | 417 | @cindex NonGNU ELPA |
| 407 | By default, Emacs downloads packages from two archives: | 418 | By default, Emacs downloads packages from two archives: |
| @@ -2827,6 +2827,14 @@ packages. | |||
| 2827 | --- | 2827 | --- |
| 2828 | *** Uninstalling a package now removes its directory from 'load-path'. | 2828 | *** Uninstalling a package now removes its directory from 'load-path'. |
| 2829 | 2829 | ||
| 2830 | +++ | ||
| 2831 | *** Packages can be reviewed before installation or upgrade. | ||
| 2832 | The user option 'package-review-policy' can configure which packages | ||
| 2833 | the user should be allowed to review before any processing takes place. | ||
| 2834 | The package review can include reading the downloaded source code, | ||
| 2835 | presenting a diff between the downloaded code and a previous | ||
| 2836 | installation or displaying a changelog. | ||
| 2837 | |||
| 2830 | ** Rcirc | 2838 | ** Rcirc |
| 2831 | 2839 | ||
| 2832 | +++ | 2840 | +++ |
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index bd5bee0a9ca..fccaf9f9f3e 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el | |||
| @@ -669,40 +669,201 @@ untar into a directory named DIR; otherwise, signal an error." | |||
| 669 | (apply #'nconc | 669 | (apply #'nconc |
| 670 | (mapcar (lambda (pair) (list (car pair) (cdr pair))) alist)))) | 670 | (mapcar (lambda (pair) (list (car pair) (cdr pair))) alist)))) |
| 671 | 671 | ||
| 672 | (defcustom package-review-policy nil | ||
| 673 | "Policy to review incoming packages before installing them. | ||
| 674 | Reviewing a package allows you to read the source code without | ||
| 675 | installing anything, compare it to previous installations of the package | ||
| 676 | and read the changelog. The default value of nil will install packages | ||
| 677 | without any additional prompts, while t reviews all packages. By | ||
| 678 | setting this user option to a list you can also selectively list what | ||
| 679 | packages and archives to review. For the former, an entry of the | ||
| 680 | form (archive STRING) will review all packages form the archive | ||
| 681 | STRING (see `package-archives'), and an entry of the form (package | ||
| 682 | SYMBOL) will review package who's name matches SYMBOL. By prefixing the | ||
| 683 | list with a symbol `not' the rules are inverted." | ||
| 684 | :type | ||
| 685 | (let ((choice '(choice :tag "Review all packages form archive" | ||
| 686 | (cons (const archive) (string :tag "Archive name")) | ||
| 687 | (cons (const package) (symbol :tag "Package name"))))) | ||
| 688 | `(choice | ||
| 689 | (const :tag "Review all packages" t) | ||
| 690 | (repeat :tag "Review these specific packages and archives" ,choice) | ||
| 691 | (cons :tag "Review the complement of these packages and archives" | ||
| 692 | (const not) (repeat ,choice)))) | ||
| 693 | :risky t | ||
| 694 | :version "31.1") | ||
| 695 | |||
| 696 | (defcustom package-review-directory temporary-file-directory | ||
| 697 | "Directory to unpack packages for review. | ||
| 698 | The value of this user option is used to rebind the variable | ||
| 699 | `temporary-file-directory'. The directory doesn't have to exist. If | ||
| 700 | that is the case, Emacs creates the directory for you. You can | ||
| 701 | therefore set the option to | ||
| 702 | |||
| 703 | (setopt package-review-directory (expand-file-name \"emacs\" (xdg-cache-home))) | ||
| 704 | |||
| 705 | if you wish to have Emacs unpack the packages in your home directory, in | ||
| 706 | case you are concerned about moving files between file systems." | ||
| 707 | :type 'directory | ||
| 708 | :version "31.1") | ||
| 709 | |||
| 710 | (defcustom package-review-diff-command | ||
| 711 | (cons diff-command | ||
| 712 | '("-u" ;unified patch formatting | ||
| 713 | "-N" ;treat absent files as empty | ||
| 714 | "-x" "'*.elc'" ;ignore byte compiled files | ||
| 715 | "-x" "'*-autoloads.el'" ;ignore the autoloads file | ||
| 716 | "-x" "'*-pkg.el'" ;ignore the package description | ||
| 717 | "-x" "'*.info'" ;ignore compiled Info files | ||
| 718 | )) | ||
| 719 | "Configuration how `package-review' should generate a Diff. | ||
| 720 | The structure of the value must be (COMMAND . SWITCHES), where | ||
| 721 | `diff-command' is rebound to be COMMAND and SWITCHES are passed to | ||
| 722 | `diff' as the SWITCHES argument if the user selects a diff-related | ||
| 723 | option during review." | ||
| 724 | :type '(cons (string :tag "Diff command") | ||
| 725 | (repeat :tag "Diff arguments" string)) | ||
| 726 | :version "31.1") | ||
| 727 | |||
| 728 | (defun package--review-p (pkg-desc) | ||
| 729 | "Return non-nil if upgrading PKG-DESC requires a review. | ||
| 730 | This package consults `package-review-policy' to determine if the user | ||
| 731 | wants to review the package prior to installation. See `package-review'." | ||
| 732 | (let ((archive (package-desc-archive pkg-desc)) | ||
| 733 | (name (package-desc-name pkg-desc))) | ||
| 734 | (pcase-exhaustive package-review-policy | ||
| 735 | ((and (pred listp) list) | ||
| 736 | (xor (any (lambda (ent) | ||
| 737 | (pcase ent | ||
| 738 | ((or `(archive . ,(pred (equal archive))) | ||
| 739 | `(package . ,(pred (eq name)))) | ||
| 740 | t) | ||
| 741 | (_ nil))) | ||
| 742 | (if (eq (car list) 'not) (cdr list) list)) | ||
| 743 | (eq (car list) 'not))) | ||
| 744 | ('t t)))) | ||
| 745 | |||
| 746 | |||
| 747 | (declare-function mail-text "sendmail" ()) | ||
| 748 | (declare-function message-goto-body "message" (&optional interactive)) | ||
| 749 | (declare-function diff-no-select "diff" (old new &optional switches no-async buf)) | ||
| 750 | |||
| 751 | (defun package-review (pkg-desc pkg-dir old-desc) | ||
| 752 | "Review the installation of PKG-DESC. | ||
| 753 | PKG-DIR is the directory where the downloaded source of PKG-DIR have | ||
| 754 | been downloaded. OLD-DESC is either a `package-desc' object of the | ||
| 755 | previous installation or nil, if there is no prior installation. If the | ||
| 756 | review fails, the function throws a symbol `review-failed' with PKG-DESC | ||
| 757 | attached." | ||
| 758 | (let ((news (let* ((pkg-dir (package-desc-dir pkg-desc)) | ||
| 759 | (file (expand-file-name "news" pkg-dir))) | ||
| 760 | (and (file-regular-p file) | ||
| 761 | (file-readable-p file) | ||
| 762 | file))) | ||
| 763 | (enable-recursive-minibuffers t) | ||
| 764 | (diff-command (car package-review-diff-command))) | ||
| 765 | (while (pcase-exhaustive | ||
| 766 | (car (read-multiple-choice | ||
| 767 | (format "Install \"%s\"?" (package-desc-name pkg-desc)) | ||
| 768 | `((?y "yes" "Proceed with installation") | ||
| 769 | (?n "no" "Abort installation") | ||
| 770 | ,@(and old-desc '((?d "diff" "Show the installation diff") | ||
| 771 | (?m "mail" "Send an email to the maintainers"))) | ||
| 772 | ,@(and news '((?c "changelog" "Show the changelog"))) | ||
| 773 | (?b "browse" "Browse the source")))) | ||
| 774 | (?y nil) | ||
| 775 | (?n | ||
| 776 | (delete-directory pkg-dir t) | ||
| 777 | (throw 'review-failed pkg-desc)) | ||
| 778 | (?d | ||
| 779 | (diff (package-desc-dir old-desc) pkg-dir (cdr package-review-diff-command) t) | ||
| 780 | t) | ||
| 781 | (?m | ||
| 782 | (require 'diff) ;for `diff-no-select' | ||
| 783 | (with-temp-buffer | ||
| 784 | (diff-no-select | ||
| 785 | (package-desc-dir old-desc) pkg-dir | ||
| 786 | (cdr package-review-diff-command) | ||
| 787 | t (current-buffer)) | ||
| 788 | ;; delete sentinel message | ||
| 789 | (goto-char (point-max)) | ||
| 790 | (forward-line -2) | ||
| 791 | (narrow-to-region (point-min) (point)) | ||
| 792 | ;; prepare mail buffer | ||
| 793 | (let ((tmp-buf (current-buffer))) | ||
| 794 | (compose-mail (with-demoted-errors "Failed to find maintainers: %S" | ||
| 795 | (package-maintainers pkg-desc))) | ||
| 796 | (pcase mail-user-agent | ||
| 797 | ('sendmail-user-agent (mail-text)) | ||
| 798 | (_ (message-goto-body))) | ||
| 799 | (insert-buffer-substring tmp-buf))) | ||
| 800 | t) | ||
| 801 | (?c | ||
| 802 | (view-file news) | ||
| 803 | t) | ||
| 804 | (?b | ||
| 805 | (dired pkg-dir "-R") ;FIXME: Is recursive dired portable? | ||
| 806 | t))))) | ||
| 807 | |||
| 672 | (declare-function dired-get-marked-files "dired") | 808 | (declare-function dired-get-marked-files "dired") |
| 673 | 809 | ||
| 674 | (defun package-unpack (pkg-desc) | 810 | (defun package-unpack (pkg-desc) |
| 675 | "Install the contents of the current buffer as a package." | 811 | "Install the contents of the current buffer as a package. |
| 812 | The argument PKG-DESC contains metadata of the yet to be installed | ||
| 813 | package. The function returns a `package-desc' object of the actually | ||
| 814 | installed package." | ||
| 676 | (let* ((name (package-desc-name pkg-desc)) | 815 | (let* ((name (package-desc-name pkg-desc)) |
| 677 | (dirname (package-desc-full-name pkg-desc)) | 816 | (full-name (package-desc-full-name pkg-desc)) |
| 678 | (pkg-dir (expand-file-name dirname package-user-dir))) | 817 | (pkg-dir (expand-file-name full-name package-user-dir)) |
| 679 | (pcase (package-desc-kind pkg-desc) | 818 | (review-p (package--review-p pkg-desc)) |
| 680 | ('dir | 819 | (unpack-dir (if review-p |
| 681 | (make-directory pkg-dir t) | 820 | (let ((temporary-file-directory package-review-directory)) |
| 682 | (let ((file-list | 821 | (make-directory temporary-file-directory t) ;ensure existence |
| 683 | (or (and (derived-mode-p 'dired-mode) | 822 | (expand-file-name |
| 684 | (dired-get-marked-files nil 'marked)) | 823 | full-name |
| 685 | (directory-files-recursively default-directory "" nil)))) | 824 | (make-temp-file "emacs-package-review-" t))) |
| 686 | (dolist (source-file file-list) | 825 | pkg-dir)) |
| 687 | (let ((target (expand-file-name | 826 | (old-desc (package--get-activatable-pkg name))) |
| 688 | (file-relative-name source-file default-directory) | 827 | (make-directory unpack-dir t) |
| 689 | pkg-dir))) | 828 | (save-window-excursion |
| 690 | (make-directory (file-name-directory target) t) | 829 | (pcase (package-desc-kind pkg-desc) |
| 691 | (copy-file source-file target t))) | 830 | ('dir |
| 692 | ;; Now that the files have been installed, this package is | 831 | (let ((file-list |
| 693 | ;; indistinguishable from a `tar' or a `single'. Let's make | 832 | (or (and (derived-mode-p 'dired-mode) |
| 694 | ;; things simple by ensuring we're one of them. | 833 | (dired-get-marked-files nil 'marked)) |
| 695 | (setf (package-desc-kind pkg-desc) | 834 | (directory-files-recursively default-directory "" nil)))) |
| 696 | (if (length> file-list 1) 'tar 'single)))) | 835 | (dolist (source-file file-list) |
| 697 | ('tar | 836 | (let ((target (expand-file-name |
| 698 | (make-directory package-user-dir t) | 837 | (file-relative-name source-file default-directory) |
| 699 | (let* ((default-directory (file-name-as-directory package-user-dir))) | 838 | unpack-dir))) |
| 700 | (package-untar-buffer dirname))) | 839 | (make-directory (file-name-directory target) t) |
| 701 | ('single | 840 | (copy-file source-file target t))) |
| 702 | (let ((el-file (expand-file-name (format "%s.el" name) pkg-dir))) | 841 | ;; Now that the files have been installed, this package is |
| 703 | (make-directory pkg-dir t) | 842 | ;; indistinguishable from a `tar' or a `single'. Let's make |
| 704 | (package--write-file-no-coding el-file))) | 843 | ;; things simple by ensuring we're one of them. |
| 705 | (kind (error "Unknown package kind: %S" kind))) | 844 | (setf (package-desc-kind pkg-desc) |
| 845 | (if (length> file-list 1) 'tar 'single)))) | ||
| 846 | ('tar | ||
| 847 | (let ((default-directory (file-name-directory unpack-dir))) | ||
| 848 | (package-untar-buffer (file-name-nondirectory unpack-dir)))) | ||
| 849 | ('single | ||
| 850 | (let ((el-file (expand-file-name (format "%s.el" name) unpack-dir))) | ||
| 851 | (package--write-file-no-coding el-file))) | ||
| 852 | (kind (error "Unknown package kind: %S" kind)))) | ||
| 853 | |||
| 854 | ;; check if the user wants to review this package | ||
| 855 | (when review-p | ||
| 856 | (unwind-protect | ||
| 857 | (progn | ||
| 858 | (save-window-excursion | ||
| 859 | (package-review pkg-desc unpack-dir old-desc)) | ||
| 860 | (make-directory package-user-dir t) | ||
| 861 | (rename-file unpack-dir pkg-dir)) | ||
| 862 | (let ((temp-dir (file-name-directory unpack-dir))) | ||
| 863 | (when (file-directory-p temp-dir) | ||
| 864 | (delete-directory temp-dir t))))) | ||
| 865 | (cl-assert (file-directory-p pkg-dir)) | ||
| 866 | |||
| 706 | (package--make-autoloads-and-stuff pkg-desc pkg-dir) | 867 | (package--make-autoloads-and-stuff pkg-desc pkg-dir) |
| 707 | ;; Update package-alist. | 868 | ;; Update package-alist. |
| 708 | (let ((new-desc (package-load-descriptor pkg-dir))) | 869 | (let ((new-desc (package-load-descriptor pkg-dir))) |
| @@ -722,8 +883,9 @@ untar into a directory named DIR; otherwise, signal an error." | |||
| 722 | (package--native-compile-async new-desc)) | 883 | (package--native-compile-async new-desc)) |
| 723 | ;; After compilation, load again any files loaded by | 884 | ;; After compilation, load again any files loaded by |
| 724 | ;; `activate-1', so that we use the byte-compiled definitions. | 885 | ;; `activate-1', so that we use the byte-compiled definitions. |
| 725 | (package--reload-previously-loaded new-desc))) | 886 | (package--reload-previously-loaded new-desc)) |
| 726 | pkg-dir)) | 887 | |
| 888 | new-desc))) | ||
| 727 | 889 | ||
| 728 | (defun package-generate-description-file (pkg-desc pkg-file) | 890 | (defun package-generate-description-file (pkg-desc pkg-file) |
| 729 | "Create the foo-pkg.el file PKG-FILE for single-file package PKG-DESC." | 891 | "Create the foo-pkg.el file PKG-FILE for single-file package PKG-DESC." |
| @@ -1740,13 +1902,16 @@ if all the in-between dependencies are also in PACKAGE-LIST." | |||
| 1740 | (cdr (assoc (package-desc-archive desc) package-archives))) | 1902 | (cdr (assoc (package-desc-archive desc) package-archives))) |
| 1741 | 1903 | ||
| 1742 | (defun package-install-from-archive (pkg-desc) | 1904 | (defun package-install-from-archive (pkg-desc) |
| 1743 | "Download and install a package defined by PKG-DESC." | 1905 | "Download and install a package defined by PKG-DESC. |
| 1906 | The function returns the new `package-desc' object of the installed | ||
| 1907 | package." | ||
| 1744 | ;; This won't happen, unless the archive is doing something wrong. | 1908 | ;; This won't happen, unless the archive is doing something wrong. |
| 1745 | (when (eq (package-desc-kind pkg-desc) 'dir) | 1909 | (when (eq (package-desc-kind pkg-desc) 'dir) |
| 1746 | (error "Can't install directory package from archive")) | 1910 | (error "Can't install directory package from archive")) |
| 1747 | (let* ((location (package-archive-base pkg-desc)) | 1911 | (let* ((location (package-archive-base pkg-desc)) |
| 1748 | (file (concat (package-desc-full-name pkg-desc) | 1912 | (file (concat (package-desc-full-name pkg-desc) |
| 1749 | (package-desc-suffix pkg-desc)))) | 1913 | (package-desc-suffix pkg-desc))) |
| 1914 | new-desc) | ||
| 1750 | (package--with-response-buffer location :file file | 1915 | (package--with-response-buffer location :file file |
| 1751 | (if (or (not (package-check-signature)) | 1916 | (if (or (not (package-check-signature)) |
| 1752 | (member (package-desc-archive pkg-desc) | 1917 | (member (package-desc-archive pkg-desc) |
| @@ -1754,7 +1919,7 @@ if all the in-between dependencies are also in PACKAGE-LIST." | |||
| 1754 | ;; If we don't care about the signature, unpack and we're | 1919 | ;; If we don't care about the signature, unpack and we're |
| 1755 | ;; done. | 1920 | ;; done. |
| 1756 | (let ((save-silently t)) | 1921 | (let ((save-silently t)) |
| 1757 | (package-unpack pkg-desc)) | 1922 | (setq new-desc (package-unpack pkg-desc))) |
| 1758 | ;; If we care, check it and *then* write the file. | 1923 | ;; If we care, check it and *then* write the file. |
| 1759 | (let ((content (buffer-string))) | 1924 | (let ((content (buffer-string))) |
| 1760 | (package--check-signature | 1925 | (package--check-signature |
| @@ -1767,7 +1932,7 @@ if all the in-between dependencies are also in PACKAGE-LIST." | |||
| 1767 | (cl-assert (not (multibyte-string-p content))) | 1932 | (cl-assert (not (multibyte-string-p content))) |
| 1768 | (insert content) | 1933 | (insert content) |
| 1769 | (let ((save-silently t)) | 1934 | (let ((save-silently t)) |
| 1770 | (package-unpack pkg-desc))) | 1935 | (setq new-desc (package-unpack pkg-desc)))) |
| 1771 | ;; Here the package has been installed successfully, mark it as | 1936 | ;; Here the package has been installed successfully, mark it as |
| 1772 | ;; signed if appropriate. | 1937 | ;; signed if appropriate. |
| 1773 | (when good-sigs | 1938 | (when good-sigs |
| @@ -1798,15 +1963,27 @@ if all the in-between dependencies are also in PACKAGE-LIST." | |||
| 1798 | (unless (save-excursion | 1963 | (unless (save-excursion |
| 1799 | (goto-char (point-min)) | 1964 | (goto-char (point-min)) |
| 1800 | (looking-at-p "[[:space:]]*\\'")) | 1965 | (looking-at-p "[[:space:]]*\\'")) |
| 1801 | (write-region nil nil readme))))))) | 1966 | (write-region nil nil readme))))) |
| 1967 | new-desc)) | ||
| 1802 | 1968 | ||
| 1803 | (defun package-download-transaction (packages) | 1969 | (defun package-download-transaction (packages) |
| 1804 | "Download and install all the packages in PACKAGES. | 1970 | "Download and install all the packages in PACKAGES. |
| 1805 | PACKAGES should be a list of `package-desc'. | 1971 | PACKAGES should be a list of `package-desc'. This function assumes that |
| 1806 | This function assumes that all package requirements in | 1972 | all package requirements in PACKAGES are satisfied, i.e. that PACKAGES |
| 1807 | PACKAGES are satisfied, i.e. that PACKAGES is computed | 1973 | is computed using `package-compute-transaction'. The function returns a |
| 1808 | using `package-compute-transaction'." | 1974 | list of `package-desc' objects that have been installed, or nil if the |
| 1809 | (mapc #'package-install-from-archive packages)) | 1975 | transaction had no effect." |
| 1976 | (let* ((installed '()) | ||
| 1977 | (pkg-desc (catch 'review-failed | ||
| 1978 | (dolist (pkg-desc packages nil) | ||
| 1979 | (push (package-install-from-archive pkg-desc) | ||
| 1980 | installed))))) | ||
| 1981 | (if pkg-desc | ||
| 1982 | (progn | ||
| 1983 | (message "Rejected `%s', reverting transaction." (package-desc-name pkg-desc)) | ||
| 1984 | (mapc #'package-delete installed) | ||
| 1985 | nil) | ||
| 1986 | installed))) | ||
| 1810 | 1987 | ||
| 1811 | (defun package--archives-initialize () | 1988 | (defun package--archives-initialize () |
| 1812 | "Make sure the list of installed and remote packages are initialized." | 1989 | "Make sure the list of installed and remote packages are initialized." |
| @@ -1855,6 +2032,10 @@ had been enabled." | |||
| 1855 | nil | 2032 | nil |
| 1856 | 'interactive))) | 2033 | 'interactive))) |
| 1857 | (cl-check-type pkg (or symbol package-desc)) | 2034 | (cl-check-type pkg (or symbol package-desc)) |
| 2035 | (when (or (and package-install-upgrade-built-in | ||
| 2036 | (package--active-built-in-p pkg)) | ||
| 2037 | (package-installed-p pkg)) | ||
| 2038 | (user-error "Package is already installed")) | ||
| 1858 | (package--archives-initialize) | 2039 | (package--archives-initialize) |
| 1859 | (add-hook 'post-command-hook #'package-menu--post-refresh) | 2040 | (add-hook 'post-command-hook #'package-menu--post-refresh) |
| 1860 | (let ((name (if (package-desc-p pkg) | 2041 | (let ((name (if (package-desc-p pkg) |
| @@ -1877,11 +2058,11 @@ had been enabled." | |||
| 1877 | (package-compute-transaction (list pkg) | 2058 | (package-compute-transaction (list pkg) |
| 1878 | (package-desc-reqs pkg))) | 2059 | (package-desc-reqs pkg))) |
| 1879 | (package-compute-transaction () (list (list pkg)))))) | 2060 | (package-compute-transaction () (list (list pkg)))))) |
| 1880 | (progn | 2061 | (if (package-download-transaction transaction) |
| 1881 | (package-download-transaction transaction) | 2062 | (progn |
| 1882 | (package--quickstart-maybe-refresh) | 2063 | (package--quickstart-maybe-refresh) |
| 1883 | (message "Package `%s' installed." name)))))) | 2064 | (message "Package `%s' installed" name)) |
| 1884 | 2065 | (error "Package `%s' not installed" name)))))) | |
| 1885 | 2066 | ||
| 1886 | (declare-function package-vc-upgrade "package-vc" (pkg)) | 2067 | (declare-function package-vc-upgrade "package-vc" (pkg)) |
| 1887 | 2068 | ||
| @@ -1900,12 +2081,17 @@ NAME should be a symbol." | |||
| 1900 | ;; `pkg-desc' will be nil when the package is an "active built-in". | 2081 | ;; `pkg-desc' will be nil when the package is an "active built-in". |
| 1901 | (if (and pkg-desc (package-vc-p pkg-desc)) | 2082 | (if (and pkg-desc (package-vc-p pkg-desc)) |
| 1902 | (package-vc-upgrade pkg-desc) | 2083 | (package-vc-upgrade pkg-desc) |
| 1903 | (when pkg-desc | 2084 | (let ((new-desc (cadr (assq name package-archive-contents)))) |
| 1904 | (package-delete pkg-desc 'force 'dont-unselect)) | 2085 | (when (or (null new-desc) |
| 1905 | (package-install name | 2086 | (version-list-= (package-desc-version pkg-desc) |
| 1906 | ;; An active built-in has never been "selected" | 2087 | (package-desc-version new-desc))) |
| 1907 | ;; before. Mark it as installed explicitly. | 2088 | (user-error "Cannot upgrade `%s'" name)) |
| 1908 | (and pkg-desc 'dont-select))))) | 2089 | (package-install new-desc |
| 2090 | ;; An active built-in has never been "selected" | ||
| 2091 | ;; before. Mark it as installed explicitly. | ||
| 2092 | (and pkg-desc 'dont-select)) | ||
| 2093 | (when pkg-desc | ||
| 2094 | (package-delete pkg-desc 'force 'dont-unselect)))))) | ||
| 1909 | 2095 | ||
| 1910 | (defun package--upgradeable-packages (&optional include-builtins) | 2096 | (defun package--upgradeable-packages (&optional include-builtins) |
| 1911 | ;; Initialize the package system to get the list of package | 2097 | ;; Initialize the package system to get the list of package |
| @@ -2040,10 +2226,20 @@ Downloads and installs required packages as needed." | |||
| 2040 | (name (package-desc-name pkg-desc))) | 2226 | (name (package-desc-name pkg-desc))) |
| 2041 | ;; Download and install the dependencies. | 2227 | ;; Download and install the dependencies. |
| 2042 | (let* ((requires (package-desc-reqs pkg-desc)) | 2228 | (let* ((requires (package-desc-reqs pkg-desc)) |
| 2043 | (transaction (package-compute-transaction nil requires))) | 2229 | (transaction (package-compute-transaction nil requires)) |
| 2044 | (package-download-transaction transaction)) | 2230 | (installed (package-download-transaction transaction))) |
| 2045 | ;; Install the package itself. | 2231 | (when (and (catch 'review-failed |
| 2046 | (package-unpack pkg-desc) | 2232 | ;; Install the package itself. |
| 2233 | (package-unpack pkg-desc) | ||
| 2234 | nil) | ||
| 2235 | (or (null transaction) installed)) | ||
| 2236 | (mapc #'package-delete installed) | ||
| 2237 | (when installed | ||
| 2238 | (message "Review uninstalled dependencies: %s" | ||
| 2239 | (mapconcat #'package-desc-full-name | ||
| 2240 | installed | ||
| 2241 | ", "))) | ||
| 2242 | (user-error "Installation aborted"))) | ||
| 2047 | (unless (package--user-selected-p name) | 2243 | (unless (package--user-selected-p name) |
| 2048 | (package--save-selected-packages | 2244 | (package--save-selected-packages |
| 2049 | (cons name package-selected-packages))) | 2245 | (cons name package-selected-packages))) |