diff options
Diffstat (limited to 'lisp/emacs-lisp/package.el')
-rw-r--r-- | lisp/emacs-lisp/package.el | 233 |
1 files changed, 154 insertions, 79 deletions
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 5fe018700a4..e23a61c58a4 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -378,10 +378,8 @@ If so, and variable `package-check-signature' is `allow-unsigned', return `allow-unsigned', otherwise return the value of variable `package-check-signature'." (if (eq package-check-signature 'allow-unsigned) - (progn - (require 'epg-config) - (and (epg-find-configuration 'OpenPGP) - 'allow-unsigned)) + (and (epg-find-configuration 'OpenPGP) + 'allow-unsigned) package-check-signature)) (defcustom package-unsigned-archives nil @@ -611,7 +609,7 @@ package." (package-archive-priority (package-desc-archive pkg-desc))) (defun package--parse-elpaignore (pkg-desc) - "Return the of regular expression to match files ignored by PKG-DESC." + "Return a list of regular expressions to match files ignored by PKG-DESC." (let* ((pkg-dir (file-name-as-directory (package-desc-dir pkg-desc))) (ignore (expand-file-name ".elpaignore" pkg-dir)) files) @@ -903,13 +901,7 @@ correspond to previously loaded files." (when reload (package--reload-previously-loaded pkg-desc)) (with-demoted-errors "Error loading autoloads: %s" - (load (package--autoloads-file-name pkg-desc) nil t)) - ;; FIXME: Since 2013 (commit 4fac34cee97a), the autoload files take - ;; care of changing the `load-path', so maybe it's time to - ;; remove this fallback code? - (unless (or (member (file-name-as-directory pkg-dir) load-path) - (member (directory-file-name pkg-dir) load-path)) - (add-to-list 'load-path pkg-dir))) + (load (package--autoloads-file-name pkg-desc) nil t))) ;; Add info node. (when (file-exists-p (expand-file-name "dir" pkg-dir)) ;; FIXME: not the friendliest, but simple. @@ -970,7 +962,6 @@ Newer versions are always activated, regardless of FORCE." "Untar the current buffer. This uses `tar-untar-buffer' from Tar mode. All files should untar into a directory named DIR; otherwise, signal an error." - (require 'tar-mode) (tar-mode) ;; Make sure everything extracts into DIR. (let ((regexp (concat "\\`" (regexp-quote (expand-file-name dir)) "/")) @@ -1200,7 +1191,7 @@ boundaries." ;; the earliest in version 31.1. The idea is to phase out the ;; requirement for a "footer line" without unduly impacting users ;; on earlier Emacs versions. See Bug#26490 for more details. - (unless (search-forward (concat ";;; " file-name ".el ends here")) + (unless (search-forward (concat ";;; " file-name ".el ends here") nil 'move) (lwarn '(package package-format) :warning "Package lacks a terminating comment")) ;; Try to include a trailing newline. @@ -1228,8 +1219,8 @@ boundaries." :url website :keywords keywords :maintainer - ;; For backward compatibility, use a single string if there's only - ;; one maintainer (the most common case). + ;; For backward compatibility, use a single cons-cell if + ;; there's only one maintainer (the most common case). (let ((maints (lm-maintainers))) (if (cdr maints) maints (car maints))) :authors (lm-authors))))) @@ -1237,15 +1228,14 @@ boundaries." "Read a `define-package' form in current buffer. Return the pkg-desc, with desc-kind set to KIND." (goto-char (point-min)) - (unwind-protect - (let* ((pkg-def-parsed (read (current-buffer))) - (pkg-desc - (when (eq (car pkg-def-parsed) 'define-package) - (apply #'package-desc-from-define - (append (cdr pkg-def-parsed)))))) - (when pkg-desc - (setf (package-desc-kind pkg-desc) kind) - pkg-desc)))) + (let* ((pkg-def-parsed (read (current-buffer))) + (pkg-desc + (when (eq (car pkg-def-parsed) 'define-package) + (apply #'package-desc-from-define + (append (cdr pkg-def-parsed)))))) + (when pkg-desc + (setf (package-desc-kind pkg-desc) kind) + pkg-desc))) (declare-function tar-get-file-descriptor "tar-mode" (file)) (declare-function tar--extract "tar-mode" (descriptor)) @@ -1992,8 +1982,11 @@ Used to populate `package-selected-packages'." (defun package--save-selected-packages (&optional value) "Set and save `package-selected-packages' to VALUE." - (when value - (setq package-selected-packages value)) + (when (or value after-init-time) + ;; It is valid to set it to nil, for example when the last package + ;; is uninstalled. But it shouldn't be done at init time, to + ;; avoid overwriting configurations that haven't yet been loaded. + (setq package-selected-packages (sort value #'string<))) (if after-init-time (customize-save-variable 'package-selected-packages package-selected-packages) (add-hook 'after-init-hook #'package--save-selected-packages))) @@ -2268,25 +2261,26 @@ had been enabled." ;;;###autoload (defun package-upgrade (name) - "Upgrade package NAME if a newer version exists. - -Currently, packages which are part of the Emacs distribution -cannot be upgraded that way. To enable upgrades of such a -package using this command, first upgrade the package to a -newer version from ELPA by using `\\<package-menu-mode-map>\\[package-menu-mark-install]' after `\\[list-packages]'." + "Upgrade package NAME if a newer version exists." (interactive (list (completing-read - "Upgrade package: " (package--upgradeable-packages) nil t))) + "Upgrade package: " (package--upgradeable-packages t) nil t))) (let* ((package (if (symbolp name) name (intern name))) - (pkg-desc (cadr (assq package package-alist)))) - (if (package-vc-p pkg-desc) + (pkg-desc (cadr (assq package package-alist))) + (package-install-upgrade-built-in (not pkg-desc))) + ;; `pkg-desc' will be nil when the package is an "active built-in". + (if (and pkg-desc (package-vc-p pkg-desc)) (package-vc-upgrade pkg-desc) - (package-delete pkg-desc 'force 'dont-unselect) - (package-install package 'dont-select)))) - -(defun package--upgradeable-packages () + (when pkg-desc + (package-delete pkg-desc 'force 'dont-unselect)) + (package-install package + ;; An active built-in has never been "selected" + ;; before. Mark it as installed explicitly. + (and pkg-desc 'dont-select))))) + +(defun package--upgradeable-packages (&optional include-builtins) ;; Initialize the package system to get the list of package ;; symbols for completion. (package--archives-initialize) @@ -2297,11 +2291,21 @@ newer version from ELPA by using `\\<package-menu-mode-map>\\[package-menu-mark- (or (let ((available (assq (car elt) package-archive-contents))) (and available - (version-list-< - (package-desc-version (cadr elt)) - (package-desc-version (cadr available))))) - (package-vc-p (cadr (assq (car elt) package-alist))))) - package-alist))) + (or (and + include-builtins + (not (package-desc-version (cadr elt)))) + (version-list-< + (package-desc-version (cadr elt)) + (package-desc-version (cadr available)))))) + (package-vc-p (cadr elt)))) + (if include-builtins + (append package-alist + (mapcan + (lambda (elt) + (when (not (assq (car elt) package-alist)) + (list (list (car elt) (package--from-builtin elt))))) + package--builtins)) + package-alist)))) ;;;###autoload (defun package-upgrade-all (&optional query) @@ -2311,8 +2315,9 @@ interactively, QUERY is always true. Currently, packages which are part of the Emacs distribution are not upgraded by this command. To enable upgrading such a package -using this command, first upgrade the package to a newer version -from ELPA by using `\\<package-menu-mode-map>\\[package-menu-mark-install]' after `\\[list-packages]'." +using this command, first upgrade the package to a newer version +from ELPA by either using `\\[package-upgrade]' or +`\\<package-menu-mode-map>\\[package-menu-mark-install]' after `\\[list-packages]'." (interactive (list (not noninteractive))) (package-refresh-contents) (let ((upgradeable (package--upgradeable-packages))) @@ -2328,12 +2333,25 @@ from ELPA by using `\\<package-menu-mode-map>\\[package-menu-mark-install]' afte (mapc #'package-upgrade upgradeable)))) (defun package--dependencies (pkg) - "Return a list of all dependencies PKG has. -This is done recursively." - ;; Can we have circular dependencies? Assume "nope". - (when-let* ((desc (cadr (assq pkg package-archive-contents))) - (deps (mapcar #'car (package-desc-reqs desc)))) - (delete-dups (apply #'nconc deps (mapcar #'package--dependencies deps))))) + "Return a list of all transitive dependencies of PKG. +If PKG is a package descriptor, the return value is a list of +package descriptors. If PKG is a symbol designating a package, +the return value is a list of symbols designating packages." + (when-let* ((desc (if (package-desc-p pkg) pkg + (cadr (assq pkg package-archive-contents))))) + ;; Can we have circular dependencies? Assume "nope". + (let ((all (named-let more ((pkg-desc desc)) + (let (deps) + (dolist (req (package-desc-reqs pkg-desc)) + (setq deps (nconc + (catch 'found + (dolist (p (apply #'append (mapcar #'cdr (package--alist)))) + (when (and (string= (car req) (package-desc-name p)) + (version-list-<= (cadr req) (package-desc-version p))) + (throw 'found (more p))))) + deps))) + (delete-dups (cons pkg-desc deps)))))) + (remq pkg (mapcar (if (package-desc-p pkg) #'identity #'package-desc-name) all))))) (defun package-strip-rcs-id (str) "Strip RCS version ID from the version string STR. @@ -2469,7 +2487,9 @@ Clean-up the corresponding .eln files if Emacs is native compiled." (when (featurep 'native-compile) (cl-loop - for file in (directory-files-recursively dir "\\.el\\'") + for file in (directory-files-recursively dir + ;; Exclude lockfiles + (rx bos (or (and "." (not "#")) (not ".")) (* nonl) ".el" eos)) do (comp-clean-up-stale-eln (comp-el-to-eln-filename file)))) (if (file-symlink-p (directory-file-name dir)) (delete-file (directory-file-name dir)) @@ -2501,8 +2521,12 @@ If NOSAVE is non-nil, the package is not removed from nil t))) (list (cdr (assoc package-name package-table)) current-prefix-arg nil)))) - (let ((dir (package-desc-dir pkg-desc)) - (name (package-desc-name pkg-desc)) + (let* ((dir (package-desc-dir pkg-desc)) + (name (package-desc-name pkg-desc)) + (new-package-alist (let ((pkgs (assq name package-alist))) + (if (null (remove pkg-desc (cdr pkgs))) + (remq pkgs package-alist) + package-alist))) pkg-used-elsewhere-by) ;; If the user is trying to delete this package, they definitely ;; don't want it marked as selected, so we remove it from @@ -2521,7 +2545,8 @@ If NOSAVE is non-nil, the package is not removed from (package-desc-full-name pkg-desc))) ((and (null force) (setq pkg-used-elsewhere-by - (package--used-elsewhere-p pkg-desc))) + (let ((package-alist new-package-alist)) + (package--used-elsewhere-p pkg-desc)))) ;See bug#65475 ;; Don't delete packages used as dependency elsewhere. (error "Package `%s' is used by `%s' as dependency, not deleting" (package-desc-full-name pkg-desc) @@ -2542,10 +2567,7 @@ If NOSAVE is non-nil, the package is not removed from (when (file-exists-p file) (delete-file file)))) ;; Update package-alist. - (let ((pkgs (assq name package-alist))) - (delete pkg-desc pkgs) - (unless (cdr pkgs) - (setq package-alist (delq pkgs package-alist)))) + (setq package-alist new-package-alist) (package--quickstart-maybe-refresh) (message "Package `%s' deleted." (package-desc-full-name pkg-desc)))))) @@ -2623,6 +2645,57 @@ will be deleted." removable)) (message "Nothing to autoremove"))))) +(defun package-isolate (packages &optional temp-init) + "Start an uncustomised Emacs and only load a set of PACKAGES. +If TEMP-INIT is non-nil, or when invoked with a prefix argument, +the Emacs user directory is set to a temporary directory." + (interactive + (cl-loop for p in (cl-loop for p in (package--alist) append (cdr p)) + unless (package-built-in-p p) + collect (cons (package-desc-full-name p) p) into table + finally return + (list (cl-loop for c in (completing-read-multiple + "Isolate packages: " table + nil t) + collect (alist-get c table nil nil #'string=)) + current-prefix-arg))) + (let* ((name (concat "package-isolate-" + (mapconcat #'package-desc-full-name packages ","))) + (all-packages (delete-consecutive-dups + (sort (append packages (mapcan #'package--dependencies packages)) + (lambda (p0 p1) + (string< (package-desc-name p0) (package-desc-name p1)))))) + initial-scratch-message package-load-list) + (with-temp-buffer + (insert ";; This is an isolated testing environment, with these packages enabled:\n\n") + (dolist (package all-packages) + (push (list (package-desc-name package) + (package-version-join (package-desc-version package))) + package-load-list) + (insert ";; - " (package-desc-full-name package)) + (unless (memq package packages) + (insert " (dependency)")) + (insert "\n")) + (insert "\n") + (setq initial-scratch-message (buffer-string))) + (apply #'start-process (concat "*" name "*") nil + (list (expand-file-name invocation-name invocation-directory) + "--quick" "--debug-init" + "--init-directory" (if temp-init + (make-temp-file name t) + user-emacs-directory) + (format "--eval=%S" + `(progn + (setq initial-scratch-message ,initial-scratch-message) + + (require 'package) + ,@(mapcar + (lambda (dir) + `(add-to-list 'package-directory-list ,dir)) + (cons package-user-dir package-directory-list)) + (setq package-load-list ',package-load-list) + (package-initialize))))))) + ;;;; Package description buffer. @@ -2738,7 +2811,8 @@ Helper function for `describe-package'." (status (if desc (package-desc-status desc) "orphan")) (incompatible-reason (package--incompatible-p desc)) (signed (if desc (package-desc-signed desc))) - (maintainer (cdr (assoc :maintainer extras))) + (maintainers (or (cdr (assoc :maintainers extras)) + (list (cdr (assoc :maintainer extras))))) (authors (cdr (assoc :authors extras))) (news (and-let* (pkg-dir ((not built-in)) @@ -2873,19 +2947,21 @@ Helper function for `describe-package'." 'action 'package-keyword-button-action) (insert " ")) (insert "\n")) - (when maintainer - (package--print-help-section "Maintainer") - (package--print-email-button maintainer)) - (when authors + (when maintainers + (unless (proper-list-p maintainers) + (setq maintainers (list maintainers))) (package--print-help-section - (if (= (length authors) 1) - "Author" - "Authors")) - (package--print-email-button (pop authors)) - ;; If there's more than one author, indent the rest correctly. - (dolist (name authors) - (insert (make-string 13 ?\s)) - (package--print-email-button name))) + (if (cdr maintainers) "Maintainers" "Maintainer")) + (dolist (maintainer maintainers) + (when (bolp) + (insert (make-string 13 ?\s))) + (package--print-email-button maintainer))) + (when authors + (package--print-help-section (if (cdr authors) "Authors" "Author")) + (dolist (author authors) + (when (bolp) + (insert (make-string 13 ?\s))) + (package--print-email-button author))) (let* ((all-pkgs (append (cdr (assq name package-alist)) (cdr (assq name package-archive-contents)) (let ((bi (assq name package--builtins))) @@ -3146,8 +3222,7 @@ The most useful commands here are: `[("Package" ,package-name-column-width package-menu--name-predicate) ("Version" ,package-version-column-width package-menu--version-predicate) ("Status" ,package-status-column-width package-menu--status-predicate) - ,@(if (cdr package-archives) - `(("Archive" ,package-archive-column-width package-menu--archive-predicate))) + ("Archive" ,package-archive-column-width package-menu--archive-predicate) ("Description" 0 package-menu--description-predicate)]) (setq tabulated-list-padding 2) (setq tabulated-list-sort-key (cons "Status" nil)) @@ -3587,9 +3662,8 @@ Return (PKG-DESC [NAME VERSION STATUS DOC])." (package-desc-version pkg))) 'font-lock-face face) ,(propertize status 'font-lock-face face) - ,@(if (cdr package-archives) - (list (propertize (or (package-desc-archive pkg) "") - 'font-lock-face face))) + ,(propertize (or (package-desc-archive pkg) "") + 'font-lock-face face) ,(propertize (package-desc-summary pkg) 'font-lock-face 'package-description)]))) @@ -4645,6 +4719,7 @@ will be signaled in that case." (package--print-email-button maint) (string-trim (substring-no-properties (buffer-string)))))))) +;;;###autoload (defun package-report-bug (desc) "Prepare a message to send to the maintainers of a package. DESC must be a `package-desc' object." |