diff options
Diffstat (limited to 'lisp/package/package-install.el')
| -rw-r--r-- | lisp/package/package-install.el | 1053 |
1 files changed, 1053 insertions, 0 deletions
diff --git a/lisp/package/package-install.el b/lisp/package/package-install.el new file mode 100644 index 00000000000..5a96fedd528 --- /dev/null +++ b/lisp/package/package-install.el | |||
| @@ -0,0 +1,1053 @@ | |||
| 1 | ;;; package-install.el --- Physical Package Management -*- lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2025 Philip Kaludercic | ||
| 4 | |||
| 5 | ;; Author: Philip Kaludercic <philipk@posteo.net> | ||
| 6 | ;; Keywords: | ||
| 7 | |||
| 8 | ;; This program is free software; you can redistribute it and/or modify | ||
| 9 | ;; it under the terms of the GNU General Public License as published by | ||
| 10 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 11 | ;; (at your option) any later version. | ||
| 12 | |||
| 13 | ;; This program is distributed in the hope that it will be useful, | ||
| 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | ;; GNU General Public License for more details. | ||
| 17 | |||
| 18 | ;; You should have received a copy of the GNU General Public License | ||
| 19 | ;; along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 20 | |||
| 21 | ;;; Commentary: | ||
| 22 | |||
| 23 | ;; | ||
| 24 | |||
| 25 | ;;; Code: | ||
| 26 | |||
| 27 | (require 'package-core) | ||
| 28 | (require 'package-misc) | ||
| 29 | (require 'package-elpa) | ||
| 30 | (require 'package-compile) | ||
| 31 | (require 'package-quickstart) | ||
| 32 | |||
| 33 | (require 'epg) | ||
| 34 | (require 'tar-mode) | ||
| 35 | (require 'lisp-mnt) | ||
| 36 | |||
| 37 | (defcustom package-install-upgrade-built-in nil | ||
| 38 | "Non-nil means that built-in packages can be upgraded via a package archive. | ||
| 39 | If disabled, then `package-install' will not suggest to replace a | ||
| 40 | built-in package with a (possibly newer) version from a package archive." | ||
| 41 | :type 'boolean | ||
| 42 | :version "29.1" | ||
| 43 | :group 'package) | ||
| 44 | |||
| 45 | (defun package-compute-transaction (packages requirements &optional seen) | ||
| 46 | "Return a list of packages to be installed, including PACKAGES. | ||
| 47 | PACKAGES should be a list of `package-desc'. | ||
| 48 | |||
| 49 | REQUIREMENTS should be a list of additional requirements; each | ||
| 50 | element in this list should have the form (PACKAGE VERSION-LIST), | ||
| 51 | where PACKAGE is a package name and VERSION-LIST is the required | ||
| 52 | version of that package. | ||
| 53 | |||
| 54 | This function recursively computes the requirements of the | ||
| 55 | packages in REQUIREMENTS, and returns a list of all the packages | ||
| 56 | that must be installed. Packages that are already installed are | ||
| 57 | not included in this list. | ||
| 58 | |||
| 59 | SEEN is used internally to detect infinite recursion." | ||
| 60 | ;; FIXME: We really should use backtracking to explore the whole | ||
| 61 | ;; search space (e.g. if foo require bar-1.3, and bar-1.4 requires toto-1.1 | ||
| 62 | ;; whereas bar-1.3 requires toto-1.0 and the user has put a hold on toto-1.0: | ||
| 63 | ;; the current code might fail to see that it could install foo by using the | ||
| 64 | ;; older bar-1.3). | ||
| 65 | (dolist (elt requirements) | ||
| 66 | (let* ((next-pkg (car elt)) | ||
| 67 | (next-version (cadr elt)) | ||
| 68 | (already ())) | ||
| 69 | (dolist (pkg packages) | ||
| 70 | (if (eq next-pkg (package-desc-name pkg)) | ||
| 71 | (setq already pkg))) | ||
| 72 | (when already | ||
| 73 | (if (version-list-<= next-version (package-desc-version already)) | ||
| 74 | ;; `next-pkg' is already in `packages', but its position there | ||
| 75 | ;; means it might be installed too late: remove it from there, so | ||
| 76 | ;; we re-add it (along with its dependencies) at an earlier place | ||
| 77 | ;; below (bug#16994). | ||
| 78 | (if (memq already seen) ;Avoid inf-loop on dependency cycles. | ||
| 79 | (message "Dependency cycle going through %S" | ||
| 80 | (package-desc-full-name already)) | ||
| 81 | (setq packages (delq already packages)) | ||
| 82 | (setq already nil)) | ||
| 83 | (error "Need package `%s-%s', but only %s is being installed" | ||
| 84 | next-pkg (package-version-join next-version) | ||
| 85 | (package-version-join (package-desc-version already))))) | ||
| 86 | (cond | ||
| 87 | (already nil) | ||
| 88 | ((package-installed-p next-pkg next-version) nil) | ||
| 89 | |||
| 90 | (t | ||
| 91 | ;; A package is required, but not installed. It might also be | ||
| 92 | ;; blocked via `package-load-list'. | ||
| 93 | (let ((pkg-descs (cdr (assq next-pkg package-archive-contents))) | ||
| 94 | (found nil) | ||
| 95 | (found-something nil) | ||
| 96 | (problem nil)) | ||
| 97 | (while (and pkg-descs (not found)) | ||
| 98 | (let* ((pkg-desc (pop pkg-descs)) | ||
| 99 | (version (package-desc-version pkg-desc)) | ||
| 100 | (disabled (package-disabled-p next-pkg version))) | ||
| 101 | (cond | ||
| 102 | ((version-list-< version next-version) | ||
| 103 | ;; pkg-descs is sorted by priority, not version, so | ||
| 104 | ;; don't error just yet. | ||
| 105 | (unless found-something | ||
| 106 | (setq found-something (package-version-join version)))) | ||
| 107 | (disabled | ||
| 108 | (unless problem | ||
| 109 | (setq problem | ||
| 110 | (if (stringp disabled) | ||
| 111 | (format-message | ||
| 112 | "Package `%s' held at version %s, but version %s required" | ||
| 113 | next-pkg disabled | ||
| 114 | (package-version-join next-version)) | ||
| 115 | (format-message "Required package `%s' is disabled" | ||
| 116 | next-pkg))))) | ||
| 117 | (t (setq found pkg-desc))))) | ||
| 118 | (unless found | ||
| 119 | (cond | ||
| 120 | (problem (error "%s" problem)) | ||
| 121 | (found-something | ||
| 122 | (error "Need package `%s-%s', but only %s is available" | ||
| 123 | next-pkg (package-version-join next-version) | ||
| 124 | found-something)) | ||
| 125 | (t | ||
| 126 | (if (eq next-pkg 'emacs) | ||
| 127 | (error "This package requires Emacs version %s" | ||
| 128 | (package-version-join next-version)) | ||
| 129 | (error (if (not next-version) | ||
| 130 | (format "Package `%s' is unavailable" next-pkg) | ||
| 131 | (format "Package `%s' (version %s) is unavailable" | ||
| 132 | next-pkg (package-version-join next-version)))))))) | ||
| 133 | (setq packages | ||
| 134 | (package-compute-transaction (cons found packages) | ||
| 135 | (package-desc-reqs found) | ||
| 136 | (cons found seen)))))))) | ||
| 137 | packages) | ||
| 138 | |||
| 139 | (defun package--get-deps (pkgs) | ||
| 140 | (let ((seen '())) | ||
| 141 | (while pkgs | ||
| 142 | (let ((pkg (pop pkgs))) | ||
| 143 | (if (memq pkg seen) | ||
| 144 | nil ;; Done already! | ||
| 145 | (let ((pkg-desc (cadr (assq pkg package-alist)))) | ||
| 146 | (when pkg-desc | ||
| 147 | (push pkg seen) | ||
| 148 | (setq pkgs (append (mapcar #'car (package-desc-reqs pkg-desc)) | ||
| 149 | pkgs))))))) | ||
| 150 | seen)) | ||
| 151 | |||
| 152 | (defun package--user-installed-p (package) | ||
| 153 | "Return non-nil if PACKAGE is a user-installed package. | ||
| 154 | PACKAGE is the package name, a symbol. Check whether the package | ||
| 155 | was installed into `package-user-dir' where we assume to have | ||
| 156 | control over." | ||
| 157 | (let* ((pkg-desc (cadr (assq package package-alist))) | ||
| 158 | (dir (package-desc-dir pkg-desc))) | ||
| 159 | (file-in-directory-p dir package-user-dir))) | ||
| 160 | |||
| 161 | (defun package--removable-packages () | ||
| 162 | "Return a list of names of packages no longer needed. | ||
| 163 | These are packages which are neither contained in | ||
| 164 | `package-selected-packages' nor a dependency of one that is." | ||
| 165 | (let ((needed (package--get-deps package-selected-packages))) | ||
| 166 | (cl-loop for p in (mapcar #'car package-alist) | ||
| 167 | unless (or (memq p needed) | ||
| 168 | ;; Do not auto-remove external packages. | ||
| 169 | (not (package--user-installed-p p))) | ||
| 170 | collect p))) | ||
| 171 | |||
| 172 | (defun package--used-elsewhere-p (pkg-desc &optional pkg-list all) | ||
| 173 | "Non-nil if PKG-DESC is a dependency of a package in PKG-LIST. | ||
| 174 | Return the first package found in PKG-LIST of which PKG is a | ||
| 175 | dependency. If ALL is non-nil, return all such packages instead. | ||
| 176 | |||
| 177 | When not specified, PKG-LIST defaults to `package-alist' | ||
| 178 | with PKG-DESC entry removed." | ||
| 179 | (unless (string= (package-desc-status pkg-desc) "obsolete") | ||
| 180 | (let* ((pkg (package-desc-name pkg-desc)) | ||
| 181 | (alist (or pkg-list | ||
| 182 | (remove (assq pkg package-alist) | ||
| 183 | package-alist)))) | ||
| 184 | (if all | ||
| 185 | (cl-loop for p in alist | ||
| 186 | if (assq pkg (package-desc-reqs (cadr p))) | ||
| 187 | collect (cadr p)) | ||
| 188 | (cl-loop for p in alist thereis | ||
| 189 | (and (assq pkg (package-desc-reqs (cadr p))) | ||
| 190 | (cadr p))))))) | ||
| 191 | |||
| 192 | (defun package--sort-deps-in-alist (package only) | ||
| 193 | "Return a list of dependencies for PACKAGE sorted by dependency. | ||
| 194 | PACKAGE is included as the first element of the returned list. | ||
| 195 | ONLY is an alist associating package names to package objects. | ||
| 196 | Only these packages will be in the return value and their cdrs are | ||
| 197 | destructively set to nil in ONLY." | ||
| 198 | (let ((out)) | ||
| 199 | (dolist (dep (package-desc-reqs package)) | ||
| 200 | (when-let* ((cell (assq (car dep) only)) | ||
| 201 | (dep-package (cdr-safe cell))) | ||
| 202 | (setcdr cell nil) | ||
| 203 | (setq out (append (package--sort-deps-in-alist dep-package only) | ||
| 204 | out)))) | ||
| 205 | (cons package out))) | ||
| 206 | |||
| 207 | (defun package--sort-by-dependence (package-list) | ||
| 208 | "Return PACKAGE-LIST sorted by dependence. | ||
| 209 | That is, any element of the returned list is guaranteed to not | ||
| 210 | directly depend on any elements that come before it. | ||
| 211 | |||
| 212 | PACKAGE-LIST is a list of `package-desc' objects. | ||
| 213 | Indirect dependencies are guaranteed to be returned in order only | ||
| 214 | if all the in-between dependencies are also in PACKAGE-LIST." | ||
| 215 | (let ((alist (mapcar (lambda (p) (cons (package-desc-name p) p)) package-list)) | ||
| 216 | out-list) | ||
| 217 | (dolist (cell alist out-list) | ||
| 218 | ;; `package--sort-deps-in-alist' destructively changes alist, so | ||
| 219 | ;; some cells might already be empty. We check this here. | ||
| 220 | (when-let* ((pkg-desc (cdr cell))) | ||
| 221 | (setcdr cell nil) | ||
| 222 | (setq out-list | ||
| 223 | (append (package--sort-deps-in-alist pkg-desc alist) | ||
| 224 | out-list)))))) | ||
| 225 | |||
| 226 | |||
| 227 | ;;; Installation Functions | ||
| 228 | ;; As opposed to the previous section (which listed some underlying | ||
| 229 | ;; functions necessary for installation), this one contains the actual | ||
| 230 | ;; functions that install packages. The package itself can be | ||
| 231 | ;; installed in a variety of ways (archives, buffer, file), but | ||
| 232 | ;; requirements (dependencies) are always satisfied by looking in | ||
| 233 | ;; `package-archive-contents'. | ||
| 234 | |||
| 235 | (defun package-archive-base (desc) | ||
| 236 | "Return the package described by DESC." | ||
| 237 | (cdr (assoc (package-desc-archive desc) package-archives))) | ||
| 238 | |||
| 239 | (defun package-desc-suffix (pkg-desc) | ||
| 240 | "Return file-name extension of package-desc object PKG-DESC. | ||
| 241 | Depending on the `package-desc-kind' of PKG-DESC, this is one of: | ||
| 242 | |||
| 243 | \\='single - \".el\" | ||
| 244 | \\='tar - \".tar\" | ||
| 245 | \\='dir - \"\" | ||
| 246 | |||
| 247 | Signal an error if the kind is none of the above." | ||
| 248 | (pcase (package-desc-kind pkg-desc) | ||
| 249 | ('single ".el") | ||
| 250 | ('tar ".tar") | ||
| 251 | ('dir "") | ||
| 252 | (kind (error "Unknown package kind: %s" kind)))) | ||
| 253 | |||
| 254 | (defun package-install-from-archive (pkg-desc) | ||
| 255 | "Download and install a package defined by PKG-DESC." | ||
| 256 | ;; This won't happen, unless the archive is doing something wrong. | ||
| 257 | (when (eq (package-desc-kind pkg-desc) 'dir) | ||
| 258 | (error "Can't install directory package from archive")) | ||
| 259 | (let* ((location (package-archive-base pkg-desc)) | ||
| 260 | (file (concat (package-desc-full-name pkg-desc) | ||
| 261 | (package-desc-suffix pkg-desc)))) | ||
| 262 | (package--with-response-buffer location :file file | ||
| 263 | (if (or (not (package-check-signature)) | ||
| 264 | (member (package-desc-archive pkg-desc) | ||
| 265 | package-unsigned-archives)) | ||
| 266 | ;; If we don't care about the signature, unpack and we're | ||
| 267 | ;; done. | ||
| 268 | (let ((save-silently t)) | ||
| 269 | (package-unpack pkg-desc)) | ||
| 270 | ;; If we care, check it and *then* write the file. | ||
| 271 | (let ((content (buffer-string))) | ||
| 272 | (package--check-signature | ||
| 273 | location file content nil | ||
| 274 | ;; This function will be called after signature checking. | ||
| 275 | (lambda (&optional good-sigs) | ||
| 276 | ;; Signature checked, unpack now. | ||
| 277 | (with-temp-buffer ;FIXME: Just use the previous current-buffer. | ||
| 278 | (set-buffer-multibyte nil) | ||
| 279 | (cl-assert (not (multibyte-string-p content))) | ||
| 280 | (insert content) | ||
| 281 | (let ((save-silently t)) | ||
| 282 | (package-unpack pkg-desc))) | ||
| 283 | ;; Here the package has been installed successfully, mark it as | ||
| 284 | ;; signed if appropriate. | ||
| 285 | (when good-sigs | ||
| 286 | ;; Write out good signatures into NAME-VERSION.signed file. | ||
| 287 | (write-region (mapconcat #'epg-signature-to-string good-sigs "\n") | ||
| 288 | nil | ||
| 289 | (expand-file-name | ||
| 290 | (concat (package-desc-full-name pkg-desc) ".signed") | ||
| 291 | package-user-dir) | ||
| 292 | nil 'silent) | ||
| 293 | ;; Update the old pkg-desc which will be shown on the description buffer. | ||
| 294 | (setf (package-desc-signed pkg-desc) t) | ||
| 295 | ;; Update the new (activated) pkg-desc as well. | ||
| 296 | (when-let* ((pkg-descs (cdr (assq (package-desc-name pkg-desc) | ||
| 297 | package-alist)))) | ||
| 298 | (setf (package-desc-signed (car pkg-descs)) t)))))))))) | ||
| 299 | |||
| 300 | ;;;###autoload | ||
| 301 | (defun package-installed-p (package &optional min-version) | ||
| 302 | "Return non-nil if PACKAGE, of MIN-VERSION or newer, is installed. | ||
| 303 | If PACKAGE is a symbol, it is the package name and MIN-VERSION | ||
| 304 | should be a version list. | ||
| 305 | |||
| 306 | If PACKAGE is a `package-desc' object, MIN-VERSION is ignored." | ||
| 307 | (cond | ||
| 308 | ((package-desc-p package) | ||
| 309 | (let ((dir (package-desc-dir package))) | ||
| 310 | (and (stringp dir) | ||
| 311 | (file-exists-p dir)))) | ||
| 312 | ((and (not package--initialized) | ||
| 313 | (null min-version) | ||
| 314 | package-activated-list) | ||
| 315 | ;; We used the quickstart: make it possible to use package-installed-p | ||
| 316 | ;; even before package is fully initialized. | ||
| 317 | (or | ||
| 318 | (memq package package-activated-list) | ||
| 319 | ;; Also check built-in packages. | ||
| 320 | (package-built-in-p package min-version))) | ||
| 321 | (t | ||
| 322 | (or | ||
| 323 | (let ((pkg-descs (cdr (assq package (package--alist))))) | ||
| 324 | (and pkg-descs | ||
| 325 | (version-list-<= min-version | ||
| 326 | (package-desc-version (car pkg-descs))))) | ||
| 327 | ;; Also check built-in packages. | ||
| 328 | (package-built-in-p package min-version))))) | ||
| 329 | |||
| 330 | (defun package-download-transaction (packages) | ||
| 331 | "Download and install all the packages in PACKAGES. | ||
| 332 | PACKAGES should be a list of `package-desc'. | ||
| 333 | This function assumes that all package requirements in | ||
| 334 | PACKAGES are satisfied, i.e. that PACKAGES is computed | ||
| 335 | using `package-compute-transaction'." | ||
| 336 | (mapc #'package-install-from-archive packages)) | ||
| 337 | |||
| 338 | ;;;###autoload | ||
| 339 | (defun package-install (pkg &optional dont-select) | ||
| 340 | "Install the package PKG. | ||
| 341 | |||
| 342 | PKG can be a `package-desc', or a symbol naming one of the available | ||
| 343 | packages in an archive in `package-archives'. | ||
| 344 | |||
| 345 | Mark the installed package as selected by adding it to | ||
| 346 | `package-selected-packages'. | ||
| 347 | |||
| 348 | When called from Lisp and optional argument DONT-SELECT is | ||
| 349 | non-nil, install the package but do not add it to | ||
| 350 | `package-selected-packages'. | ||
| 351 | |||
| 352 | If PKG is a `package-desc' and it is already installed, don't try | ||
| 353 | to install it but still mark it as selected. | ||
| 354 | |||
| 355 | If the command is invoked with a prefix argument, it will allow | ||
| 356 | upgrading of built-in packages, as if `package-install-upgrade-built-in' | ||
| 357 | had been enabled." | ||
| 358 | (interactive | ||
| 359 | (progn | ||
| 360 | ;; Initialize the package system to get the list of package | ||
| 361 | ;; symbols for completion. | ||
| 362 | (package--archives-initialize) | ||
| 363 | (list (intern (completing-read | ||
| 364 | "Install package: " | ||
| 365 | (mapcan | ||
| 366 | (lambda (elt) | ||
| 367 | (and (or (and (or current-prefix-arg | ||
| 368 | package-install-upgrade-built-in) | ||
| 369 | (package--active-built-in-p (car elt))) | ||
| 370 | (not (package-installed-p (car elt)))) | ||
| 371 | (list (symbol-name (car elt))))) | ||
| 372 | package-archive-contents) | ||
| 373 | nil t)) | ||
| 374 | nil))) | ||
| 375 | (cl-check-type pkg (or symbol package-desc)) | ||
| 376 | (package--archives-initialize) | ||
| 377 | (when (fboundp 'package-menu--post-refresh) | ||
| 378 | (add-hook 'post-command-hook #'package-menu--post-refresh)) | ||
| 379 | (let ((name (if (package-desc-p pkg) | ||
| 380 | (package-desc-name pkg) | ||
| 381 | pkg))) | ||
| 382 | (unless (or dont-select (package--user-selected-p name)) | ||
| 383 | (package--save-selected-packages | ||
| 384 | (cons name package-selected-packages))) | ||
| 385 | (when (and (or current-prefix-arg package-install-upgrade-built-in) | ||
| 386 | (package--active-built-in-p pkg)) | ||
| 387 | (setq pkg (or (cadr (assq name package-archive-contents)) pkg))) | ||
| 388 | (if-let* ((transaction | ||
| 389 | (if (package-desc-p pkg) | ||
| 390 | (unless (package-installed-p pkg) | ||
| 391 | (package-compute-transaction (list pkg) | ||
| 392 | (package-desc-reqs pkg))) | ||
| 393 | (package-compute-transaction () (list (list pkg)))))) | ||
| 394 | (progn | ||
| 395 | (package-download-transaction transaction) | ||
| 396 | (package--quickstart-maybe-refresh) | ||
| 397 | (message "Package `%s' installed." name)) | ||
| 398 | (message "`%s' is already installed" name)))) | ||
| 399 | |||
| 400 | (declare-function package-vc-upgrade "package-vc" (pkg)) | ||
| 401 | |||
| 402 | ;;;###autoload | ||
| 403 | (defun package-upgrade (name) | ||
| 404 | "Upgrade package NAME if a newer version exists. | ||
| 405 | |||
| 406 | NAME should be a symbol." | ||
| 407 | (interactive | ||
| 408 | (list (intern (completing-read | ||
| 409 | "Upgrade package: " | ||
| 410 | (package--upgradeable-packages t) nil t)))) | ||
| 411 | (cl-check-type name symbol) | ||
| 412 | (let* ((pkg-desc (cadr (assq name package-alist))) | ||
| 413 | (package-install-upgrade-built-in (not pkg-desc))) | ||
| 414 | ;; `pkg-desc' will be nil when the package is an "active built-in". | ||
| 415 | (if (and pkg-desc (package-vc-p pkg-desc)) | ||
| 416 | (package-vc-upgrade pkg-desc) | ||
| 417 | (when pkg-desc | ||
| 418 | (package-delete pkg-desc 'force 'dont-unselect)) | ||
| 419 | (package-install name | ||
| 420 | ;; An active built-in has never been "selected" | ||
| 421 | ;; before. Mark it as installed explicitly. | ||
| 422 | (and pkg-desc 'dont-select))))) | ||
| 423 | |||
| 424 | (defun package--upgradeable-packages (&optional include-builtins) | ||
| 425 | ;; Initialize the package system to get the list of package | ||
| 426 | ;; symbols for completion. | ||
| 427 | (package--archives-initialize) | ||
| 428 | (mapcar | ||
| 429 | #'car | ||
| 430 | (seq-filter | ||
| 431 | (lambda (elt) | ||
| 432 | (or (let ((available | ||
| 433 | (assq (car elt) package-archive-contents))) | ||
| 434 | (and available | ||
| 435 | (or (and | ||
| 436 | include-builtins | ||
| 437 | (not (package-desc-version (cadr elt)))) | ||
| 438 | (version-list-< | ||
| 439 | (package-desc-version (cadr elt)) | ||
| 440 | (package-desc-version (cadr available)))))) | ||
| 441 | (package-vc-p (cadr elt)))) | ||
| 442 | (if include-builtins | ||
| 443 | (append package-alist | ||
| 444 | (mapcan | ||
| 445 | (lambda (elt) | ||
| 446 | (when (not (assq (car elt) package-alist)) | ||
| 447 | (list (list (car elt) (package--from-builtin elt))))) | ||
| 448 | package--builtins)) | ||
| 449 | package-alist)))) | ||
| 450 | |||
| 451 | ;;;###autoload | ||
| 452 | (defun package-upgrade-all (&optional query) | ||
| 453 | "Refresh package list and upgrade all packages. | ||
| 454 | If QUERY, ask the user before upgrading packages. When called | ||
| 455 | interactively, QUERY is always true. | ||
| 456 | |||
| 457 | Currently, packages which are part of the Emacs distribution are | ||
| 458 | not upgraded by this command. To enable upgrading such a package | ||
| 459 | using this command, first upgrade the package to a newer version | ||
| 460 | from ELPA by either using `\\[package-upgrade]' or | ||
| 461 | `\\<package-menu-mode-map>\\[package-menu-mark-install]' after `\\[list-packages]'." | ||
| 462 | (interactive (list (not noninteractive))) | ||
| 463 | (package-refresh-contents) | ||
| 464 | (let ((upgradeable (package--upgradeable-packages))) | ||
| 465 | (if (not upgradeable) | ||
| 466 | (message "No packages to upgrade") | ||
| 467 | (when (and query | ||
| 468 | (not (yes-or-no-p | ||
| 469 | (if (length= upgradeable 1) | ||
| 470 | "One package to upgrade. Do it? " | ||
| 471 | (format "%s packages to upgrade. Do it?" | ||
| 472 | (length upgradeable)))))) | ||
| 473 | (user-error "Upgrade aborted")) | ||
| 474 | (mapc #'package-upgrade upgradeable)))) | ||
| 475 | |||
| 476 | (defun package--dependencies (pkg) | ||
| 477 | "Return a list of all transitive dependencies of PKG. | ||
| 478 | If PKG is a package descriptor, the return value is a list of | ||
| 479 | package descriptors. If PKG is a symbol designating a package, | ||
| 480 | the return value is a list of symbols designating packages." | ||
| 481 | (when-let* ((desc (if (package-desc-p pkg) pkg | ||
| 482 | (cadr (assq pkg package-archive-contents))))) | ||
| 483 | ;; Can we have circular dependencies? Assume "nope". | ||
| 484 | (let ((all (named-let more ((pkg-desc desc)) | ||
| 485 | (let (deps) | ||
| 486 | (dolist (req (package-desc-reqs pkg-desc)) | ||
| 487 | (setq deps (nconc | ||
| 488 | (catch 'found | ||
| 489 | (dolist (p (apply #'append (mapcar #'cdr (package--alist)))) | ||
| 490 | (when (and (string= (car req) (package-desc-name p)) | ||
| 491 | (version-list-<= (cadr req) (package-desc-version p))) | ||
| 492 | (throw 'found (more p))))) | ||
| 493 | deps))) | ||
| 494 | (delete-dups (cons pkg-desc deps)))))) | ||
| 495 | (remq pkg (mapcar (if (package-desc-p pkg) #'identity #'package-desc-name) all))))) | ||
| 496 | |||
| 497 | (defun package-buffer-info () | ||
| 498 | "Return a `package-desc' describing the package in the current buffer. | ||
| 499 | |||
| 500 | If the buffer does not contain a conforming package, signal an | ||
| 501 | error. If there is a package, narrow the buffer to the file's | ||
| 502 | boundaries." | ||
| 503 | (goto-char (point-min)) | ||
| 504 | (unless (re-search-forward "^;;; \\([^ ]*\\)\\.el ---[ \t]*\\(.*?\\)[ \t]*\\(-\\*-.*-\\*-[ \t]*\\)?$" nil t) | ||
| 505 | (error "Package lacks a file header")) | ||
| 506 | (let ((file-name (match-string-no-properties 1)) | ||
| 507 | (desc (match-string-no-properties 2))) | ||
| 508 | (require 'lisp-mnt) | ||
| 509 | (let* ((version-info (lm-package-version)) | ||
| 510 | (pkg-version (package-strip-rcs-id version-info)) | ||
| 511 | (keywords (lm-keywords-list)) | ||
| 512 | (website (lm-website))) | ||
| 513 | (unless pkg-version | ||
| 514 | (if version-info | ||
| 515 | (error "Unrecognized package version: %s" version-info) | ||
| 516 | (error "Package lacks a \"Version\" or \"Package-Version\" header"))) | ||
| 517 | (package-desc-from-define | ||
| 518 | file-name pkg-version desc | ||
| 519 | (lm-package-requires) | ||
| 520 | :kind 'single | ||
| 521 | :url website | ||
| 522 | :keywords keywords | ||
| 523 | :maintainer | ||
| 524 | ;; For backward compatibility, use a single cons-cell if | ||
| 525 | ;; there's only one maintainer (the most common case). | ||
| 526 | (let ((maints (lm-maintainers))) (if (cdr maints) maints (car maints))) | ||
| 527 | :authors (lm-authors))))) | ||
| 528 | |||
| 529 | (defun package-dir-info () | ||
| 530 | "Find package information for a directory. | ||
| 531 | The return result is a `package-desc'." | ||
| 532 | (cl-assert (derived-mode-p 'dired-mode)) | ||
| 533 | (let* ((desc-file (package--description-file default-directory))) | ||
| 534 | (if (file-readable-p desc-file) | ||
| 535 | (with-temp-buffer | ||
| 536 | (insert-file-contents desc-file) | ||
| 537 | (package--read-pkg-desc 'dir)) | ||
| 538 | (catch 'found | ||
| 539 | (let ((files (or (and (derived-mode-p 'dired-mode) | ||
| 540 | (dired-get-marked-files)) | ||
| 541 | (directory-files-recursively default-directory "\\.el\\'")))) | ||
| 542 | ;; We sort the file names in lexicographical order, to ensure | ||
| 543 | ;; that we check shorter file names first (ie. those further | ||
| 544 | ;; up in the directory structure). | ||
| 545 | (dolist (file (sort files)) | ||
| 546 | ;; The file may be a link to a nonexistent file; e.g., a | ||
| 547 | ;; lock file. | ||
| 548 | (when (file-exists-p file) | ||
| 549 | (with-temp-buffer | ||
| 550 | (insert-file-contents file) | ||
| 551 | ;; When we find the file with the data, | ||
| 552 | (when-let* ((info (ignore-errors (package-buffer-info)))) | ||
| 553 | (setf (package-desc-kind info) 'dir) | ||
| 554 | (throw 'found info)))))) | ||
| 555 | (error "No .el files with package headers in `%s'" default-directory))))) | ||
| 556 | |||
| 557 | ;;;###autoload | ||
| 558 | (defun package-install-from-buffer () | ||
| 559 | "Install a package from the current buffer. | ||
| 560 | The current buffer is assumed to be a single .el or .tar file or | ||
| 561 | a directory. These must follow the packaging guidelines (see | ||
| 562 | info node `(elisp)Packaging'). | ||
| 563 | |||
| 564 | Specially, if current buffer is a directory, the -pkg.el | ||
| 565 | description file is not mandatory, in which case the information | ||
| 566 | is derived from the main .el file in the directory. Using Dired, | ||
| 567 | you can restrict what files to install by marking specific files. | ||
| 568 | |||
| 569 | Downloads and installs required packages as needed." | ||
| 570 | (interactive) | ||
| 571 | (let* ((pkg-desc | ||
| 572 | (cond | ||
| 573 | ((derived-mode-p 'dired-mode) | ||
| 574 | ;; This is the only way a package-desc object with a `dir' | ||
| 575 | ;; desc-kind can be created. Such packages can't be | ||
| 576 | ;; uploaded or installed from archives, they can only be | ||
| 577 | ;; installed from local buffers or directories. | ||
| 578 | (package-dir-info)) | ||
| 579 | ((derived-mode-p 'tar-mode) | ||
| 580 | (package-tar-file-info)) | ||
| 581 | (t | ||
| 582 | ;; Package headers should be parsed from decoded text | ||
| 583 | ;; (see Bug#48137) where possible. | ||
| 584 | (if (and (eq buffer-file-coding-system 'no-conversion) | ||
| 585 | buffer-file-name) | ||
| 586 | (let* ((package-buffer (current-buffer)) | ||
| 587 | (decoding-system | ||
| 588 | (car (find-operation-coding-system | ||
| 589 | 'insert-file-contents | ||
| 590 | (cons buffer-file-name | ||
| 591 | package-buffer))))) | ||
| 592 | (with-temp-buffer | ||
| 593 | (insert-buffer-substring package-buffer) | ||
| 594 | (decode-coding-region (point-min) (point-max) | ||
| 595 | decoding-system) | ||
| 596 | (package-buffer-info))) | ||
| 597 | |||
| 598 | (save-excursion | ||
| 599 | (package-buffer-info)))))) | ||
| 600 | (name (package-desc-name pkg-desc))) | ||
| 601 | ;; Download and install the dependencies. | ||
| 602 | (let* ((requires (package-desc-reqs pkg-desc)) | ||
| 603 | (transaction (package-compute-transaction nil requires))) | ||
| 604 | (package-download-transaction transaction)) | ||
| 605 | ;; Install the package itself. | ||
| 606 | (package-unpack pkg-desc) | ||
| 607 | (unless (package--user-selected-p name) | ||
| 608 | (package--save-selected-packages | ||
| 609 | (cons name package-selected-packages))) | ||
| 610 | (package--quickstart-maybe-refresh) | ||
| 611 | pkg-desc)) | ||
| 612 | |||
| 613 | ;;;###autoload | ||
| 614 | (defun package-install-file (file) | ||
| 615 | "Install a package from FILE. | ||
| 616 | The file can either be a tar file, an Emacs Lisp file, or a | ||
| 617 | directory." | ||
| 618 | (interactive "fPackage file name: ") | ||
| 619 | (with-temp-buffer | ||
| 620 | (if (file-directory-p file) | ||
| 621 | (progn | ||
| 622 | (setq default-directory file) | ||
| 623 | (dired-mode)) | ||
| 624 | (insert-file-contents-literally file) | ||
| 625 | (set-visited-file-name file) | ||
| 626 | (set-buffer-modified-p nil) | ||
| 627 | (when (string-match "\\.tar\\'" file) (tar-mode))) | ||
| 628 | (package-install-from-buffer))) | ||
| 629 | |||
| 630 | |||
| 631 | |||
| 632 | ;;;###autoload | ||
| 633 | (defun package-install-selected-packages (&optional noconfirm) | ||
| 634 | "Ensure packages in `package-selected-packages' are installed. | ||
| 635 | If some packages are not installed, propose to install them. | ||
| 636 | |||
| 637 | If optional argument NOCONFIRM is non-nil, or when invoked with a prefix | ||
| 638 | argument, don't ask for confirmation to install packages." | ||
| 639 | (interactive "P") | ||
| 640 | (package--archives-initialize) | ||
| 641 | ;; We don't need to populate `package-selected-packages' before | ||
| 642 | ;; using here, because the outcome is the same either way (nothing | ||
| 643 | ;; gets installed). | ||
| 644 | (if (not package-selected-packages) | ||
| 645 | (message "`package-selected-packages' is empty, nothing to install") | ||
| 646 | (let* ((not-installed (seq-remove #'package-installed-p package-selected-packages)) | ||
| 647 | (available (seq-filter (lambda (p) (assq p package-archive-contents)) not-installed)) | ||
| 648 | (difference (- (length not-installed) (length available)))) | ||
| 649 | (cond | ||
| 650 | (available | ||
| 651 | (when (or noconfirm | ||
| 652 | (y-or-n-p | ||
| 653 | (format "Packages to install: %d (%s), proceed? " | ||
| 654 | (length available) | ||
| 655 | (mapconcat #'symbol-name available " ")))) | ||
| 656 | (mapc (lambda (p) (package-install p 'dont-select)) available))) | ||
| 657 | ((> difference 0) | ||
| 658 | (message (substitute-command-keys | ||
| 659 | "Packages that are not available: %d (the rest is already \ | ||
| 660 | installed), maybe you need to \\[package-refresh-contents]") | ||
| 661 | difference)) | ||
| 662 | (t | ||
| 663 | (message "All your packages are already installed")))))) | ||
| 664 | |||
| 665 | (defun package--newest-p (pkg) | ||
| 666 | "Return non-nil if PKG is the newest package with its name." | ||
| 667 | (equal (cadr (assq (package-desc-name pkg) package-alist)) | ||
| 668 | pkg)) | ||
| 669 | |||
| 670 | (declare-function comp-el-to-eln-filename "comp.c") | ||
| 671 | (defvar package-vc-repository-store) | ||
| 672 | (defun package--delete-directory (dir) | ||
| 673 | "Delete PKG-DESC directory DIR recursively. | ||
| 674 | Clean-up the corresponding .eln files if Emacs is native | ||
| 675 | compiled." | ||
| 676 | (when (featurep 'native-compile) | ||
| 677 | (cl-loop | ||
| 678 | for file in (directory-files-recursively dir | ||
| 679 | ;; Exclude lockfiles | ||
| 680 | (rx bos (or (and "." (not "#")) (not ".")) (* nonl) ".el" eos)) | ||
| 681 | do (comp-clean-up-stale-eln (comp-el-to-eln-filename file)))) | ||
| 682 | (if (file-symlink-p (directory-file-name dir)) | ||
| 683 | (delete-file (directory-file-name dir)) | ||
| 684 | (delete-directory dir t))) | ||
| 685 | |||
| 686 | (defun package-delete (pkg-desc &optional force nosave) | ||
| 687 | "Delete package PKG-DESC. | ||
| 688 | |||
| 689 | Argument PKG-DESC is the full description of the package, for example as | ||
| 690 | obtained by `package-get-descriptor'. Interactively, prompt the user | ||
| 691 | for the package name and version. | ||
| 692 | |||
| 693 | When package is used elsewhere as dependency of another package, | ||
| 694 | refuse deleting it and return an error. | ||
| 695 | If prefix argument FORCE is non-nil, package will be deleted even | ||
| 696 | if it is used elsewhere. | ||
| 697 | If NOSAVE is non-nil, the package is not removed from | ||
| 698 | `package-selected-packages'." | ||
| 699 | (interactive | ||
| 700 | (progn | ||
| 701 | (let* ((package-table | ||
| 702 | (mapcar | ||
| 703 | (lambda (p) (cons (package-desc-full-name p) p)) | ||
| 704 | (delq nil | ||
| 705 | (mapcar (lambda (p) (unless (package-built-in-p p) p)) | ||
| 706 | (apply #'append (mapcar #'cdr (package--alist))))))) | ||
| 707 | (package-name (completing-read "Delete package: " | ||
| 708 | (mapcar #'car package-table) | ||
| 709 | nil t))) | ||
| 710 | (list (cdr (assoc package-name package-table)) | ||
| 711 | current-prefix-arg nil)))) | ||
| 712 | (let* ((dir (package-desc-dir pkg-desc)) | ||
| 713 | (name (package-desc-name pkg-desc)) | ||
| 714 | (new-package-alist (let ((pkgs (assq name package-alist))) | ||
| 715 | (if (null (remove pkg-desc (cdr pkgs))) | ||
| 716 | (remq pkgs package-alist) | ||
| 717 | package-alist))) | ||
| 718 | pkg-used-elsewhere-by) | ||
| 719 | ;; If the user is trying to delete this package, they definitely | ||
| 720 | ;; don't want it marked as selected, so we remove it from | ||
| 721 | ;; `package-selected-packages' even if it can't be deleted. | ||
| 722 | (when (and (null nosave) | ||
| 723 | (package--user-selected-p name) | ||
| 724 | ;; Don't deselect if this is an older version of an | ||
| 725 | ;; upgraded package. | ||
| 726 | (package--newest-p pkg-desc)) | ||
| 727 | (package--save-selected-packages (remove name package-selected-packages))) | ||
| 728 | (cond ((not (string-prefix-p (file-name-as-directory | ||
| 729 | (expand-file-name package-user-dir)) | ||
| 730 | (expand-file-name dir))) | ||
| 731 | ;; Don't delete "system" packages. | ||
| 732 | (error "Package `%s' is a system package, not deleting" | ||
| 733 | (package-desc-full-name pkg-desc))) | ||
| 734 | ((and (null force) | ||
| 735 | (setq pkg-used-elsewhere-by | ||
| 736 | (let ((package-alist new-package-alist)) | ||
| 737 | (package--used-elsewhere-p pkg-desc)))) ;See bug#65475 | ||
| 738 | ;; Don't delete packages used as dependency elsewhere. | ||
| 739 | (error "Package `%s' is used by `%s' as dependency, not deleting" | ||
| 740 | (package-desc-full-name pkg-desc) | ||
| 741 | (package-desc-name pkg-used-elsewhere-by))) | ||
| 742 | (t | ||
| 743 | (add-hook 'post-command-hook 'package-menu--post-refresh) | ||
| 744 | (package--delete-directory dir) | ||
| 745 | ;; Remove NAME-VERSION.signed and NAME-readme.txt files. | ||
| 746 | ;; | ||
| 747 | ;; NAME-readme.txt files are no longer created, but they | ||
| 748 | ;; may be left around from an earlier install. | ||
| 749 | (dolist (suffix '(".signed" "readme.txt")) | ||
| 750 | (let* ((version (package-version-join (package-desc-version pkg-desc))) | ||
| 751 | (file (concat (if (string= suffix ".signed") | ||
| 752 | dir | ||
| 753 | (substring dir 0 (- (length version)))) | ||
| 754 | suffix))) | ||
| 755 | (when (file-exists-p file) | ||
| 756 | (delete-file file)))) | ||
| 757 | ;; Update package-alist. | ||
| 758 | (setq package-alist new-package-alist) | ||
| 759 | (package--quickstart-maybe-refresh) | ||
| 760 | (message "Package `%s' deleted." | ||
| 761 | (package-desc-full-name pkg-desc)))))) | ||
| 762 | |||
| 763 | ;;;###autoload | ||
| 764 | (defun package-reinstall (pkg) | ||
| 765 | "Reinstall package PKG. | ||
| 766 | PKG should be either a symbol, the package name, or a `package-desc' | ||
| 767 | object." | ||
| 768 | (interactive | ||
| 769 | (progn | ||
| 770 | (package--archives-initialize) | ||
| 771 | (list (intern (completing-read | ||
| 772 | "Reinstall package: " | ||
| 773 | (mapcar #'symbol-name | ||
| 774 | (mapcar #'car package-alist))))))) | ||
| 775 | (package--archives-initialize) | ||
| 776 | (package-delete | ||
| 777 | (if (package-desc-p pkg) pkg (cadr (assq pkg package-alist))) | ||
| 778 | 'force 'nosave) | ||
| 779 | (package-install pkg 'dont-select)) | ||
| 780 | |||
| 781 | ;;;###autoload | ||
| 782 | (defun package-autoremove (&optional noconfirm) | ||
| 783 | "Remove packages that are no longer needed. | ||
| 784 | |||
| 785 | Packages that are no more needed by other packages in | ||
| 786 | `package-selected-packages' and their dependencies | ||
| 787 | will be deleted. | ||
| 788 | |||
| 789 | If optional argument NOCONFIRM is non-nil, or when invoked with a prefix | ||
| 790 | argument, don't ask for confirmation to install packages." | ||
| 791 | (interactive "P") | ||
| 792 | ;; If `package-selected-packages' is nil, it would make no sense to | ||
| 793 | ;; try to populate it here, because then `package-autoremove' will | ||
| 794 | ;; do absolutely nothing. | ||
| 795 | (when (or noconfirm | ||
| 796 | package-selected-packages | ||
| 797 | (yes-or-no-p | ||
| 798 | (format-message | ||
| 799 | "`package-selected-packages' is empty! Really remove ALL packages? "))) | ||
| 800 | (let ((removable (package--removable-packages))) | ||
| 801 | (if removable | ||
| 802 | (when (or noconfirm | ||
| 803 | (y-or-n-p | ||
| 804 | (format "Packages to delete: %d (%s), proceed? " | ||
| 805 | (length removable) | ||
| 806 | (mapconcat #'symbol-name removable " ")))) | ||
| 807 | (mapc (lambda (p) | ||
| 808 | (package-delete (cadr (assq p package-alist)) t)) | ||
| 809 | removable)) | ||
| 810 | (message "Nothing to autoremove"))))) | ||
| 811 | |||
| 812 | |||
| 813 | ;;;; Autoload | ||
| 814 | (declare-function autoload-rubric "autoload" (file &optional type feature)) | ||
| 815 | |||
| 816 | (defun package-autoload-ensure-default-file (file) | ||
| 817 | "Make sure that the autoload file FILE exists and if not create it." | ||
| 818 | (declare (obsolete nil "29.1")) | ||
| 819 | (unless (file-exists-p file) | ||
| 820 | (require 'autoload) | ||
| 821 | (let ((coding-system-for-write 'utf-8-emacs-unix)) | ||
| 822 | (with-suppressed-warnings ((obsolete autoload-rubric)) | ||
| 823 | (write-region (autoload-rubric file "package" nil) | ||
| 824 | nil file nil 'silent)))) | ||
| 825 | file) | ||
| 826 | |||
| 827 | (defvar autoload-timestamps) | ||
| 828 | (defvar version-control) | ||
| 829 | |||
| 830 | (defun package-generate-autoloads (name pkg-dir) | ||
| 831 | "Generate autoloads in PKG-DIR for package named NAME." | ||
| 832 | (let* ((auto-name (format "%s-autoloads.el" name)) | ||
| 833 | ;;(ignore-name (concat name "-pkg.el")) | ||
| 834 | (output-file (expand-file-name auto-name pkg-dir)) | ||
| 835 | ;; We don't need 'em, and this makes the output reproducible. | ||
| 836 | (autoload-timestamps nil) | ||
| 837 | (backup-inhibited t) | ||
| 838 | (version-control 'never)) | ||
| 839 | (loaddefs-generate | ||
| 840 | pkg-dir output-file nil | ||
| 841 | (prin1-to-string | ||
| 842 | '(add-to-list | ||
| 843 | 'load-path | ||
| 844 | ;; Add the directory that will contain the autoload file to | ||
| 845 | ;; the load path. We don't hard-code `pkg-dir', to avoid | ||
| 846 | ;; issues if the package directory is moved around. | ||
| 847 | ;; `loaddefs-generate' has code to do this for us, but it's | ||
| 848 | ;; not currently exposed. (Bug#63625) | ||
| 849 | (or (and load-file-name | ||
| 850 | (directory-file-name | ||
| 851 | (file-name-directory load-file-name))) | ||
| 852 | (car load-path))))) | ||
| 853 | (let ((buf (find-buffer-visiting output-file))) | ||
| 854 | (when buf (kill-buffer buf))) | ||
| 855 | auto-name)) | ||
| 856 | |||
| 857 | (defun package--make-autoloads-and-stuff (pkg-desc pkg-dir) | ||
| 858 | "Generate autoloads, description file, etc., for PKG-DESC installed at PKG-DIR." | ||
| 859 | (package-generate-autoloads (package-desc-name pkg-desc) pkg-dir) | ||
| 860 | (let ((desc-file (expand-file-name (package--description-file pkg-dir) | ||
| 861 | pkg-dir))) | ||
| 862 | (unless (file-exists-p desc-file) | ||
| 863 | (package-generate-description-file pkg-desc desc-file))) | ||
| 864 | ;; FIXME: Create foo.info and dir file from foo.texi? | ||
| 865 | ) | ||
| 866 | |||
| 867 | (defun package-tar-file-info () | ||
| 868 | "Find package information for a tar file. | ||
| 869 | The return result is a `package-desc'." | ||
| 870 | (cl-assert (derived-mode-p 'tar-mode)) | ||
| 871 | (let* ((dir-name (named-let loop | ||
| 872 | ((filename (tar-header-name (car tar-parse-info)))) | ||
| 873 | (let ((dirname (file-name-directory filename))) | ||
| 874 | ;; The first file can be in a subdir: look for the top. | ||
| 875 | (if dirname (loop (directory-file-name dirname)) | ||
| 876 | (file-name-as-directory filename))))) | ||
| 877 | (desc-file (package--description-file dir-name)) | ||
| 878 | (tar-desc (tar-get-file-descriptor (concat dir-name desc-file)))) | ||
| 879 | (unless tar-desc | ||
| 880 | (error "No package descriptor file found")) | ||
| 881 | (with-current-buffer (tar--extract tar-desc) | ||
| 882 | (unwind-protect | ||
| 883 | (or (package--read-pkg-desc 'tar) | ||
| 884 | (error "Can't find define-package in %s" | ||
| 885 | (tar-header-name tar-desc))) | ||
| 886 | (kill-buffer (current-buffer)))))) | ||
| 887 | |||
| 888 | (defun package-untar-buffer (dir) | ||
| 889 | "Untar the current buffer. | ||
| 890 | This uses `tar-untar-buffer' from Tar mode. All files should | ||
| 891 | untar into a directory named DIR; otherwise, signal an error." | ||
| 892 | (tar-mode) | ||
| 893 | ;; Make sure everything extracts into DIR. | ||
| 894 | (let ((regexp (concat "\\`" (regexp-quote (expand-file-name dir)) "/")) | ||
| 895 | (case-fold-search (file-name-case-insensitive-p dir))) | ||
| 896 | (dolist (tar-data tar-parse-info) | ||
| 897 | (let ((name (expand-file-name (tar-header-name tar-data)))) | ||
| 898 | (or (string-match regexp name) | ||
| 899 | ;; Tarballs created by some utilities don't list | ||
| 900 | ;; directories with a trailing slash (Bug#13136). | ||
| 901 | (and (string-equal (expand-file-name dir) name) | ||
| 902 | (eq (tar-header-link-type tar-data) 5)) | ||
| 903 | (error "Package does not untar cleanly into directory %s/" dir))))) | ||
| 904 | (tar-untar-buffer)) | ||
| 905 | |||
| 906 | (declare-function dired-get-marked-files "dired") | ||
| 907 | |||
| 908 | (defun package-unpack (pkg-desc) | ||
| 909 | "Install the contents of the current buffer as a package." | ||
| 910 | (let* ((name (package-desc-name pkg-desc)) | ||
| 911 | (dirname (package-desc-full-name pkg-desc)) | ||
| 912 | (pkg-dir (expand-file-name dirname package-user-dir))) | ||
| 913 | (pcase (package-desc-kind pkg-desc) | ||
| 914 | ('dir | ||
| 915 | (make-directory pkg-dir t) | ||
| 916 | (let ((file-list | ||
| 917 | (or (and (derived-mode-p 'dired-mode) | ||
| 918 | (dired-get-marked-files)) | ||
| 919 | (directory-files-recursively default-directory "" nil)))) | ||
| 920 | (dolist (source-file file-list) | ||
| 921 | (let ((target (expand-file-name | ||
| 922 | (file-relative-name source-file default-directory) | ||
| 923 | pkg-dir))) | ||
| 924 | (make-directory (file-name-directory target) t) | ||
| 925 | (copy-file source-file target t))) | ||
| 926 | ;; Now that the files have been installed, this package is | ||
| 927 | ;; indistinguishable from a `tar' or a `single'. Let's make | ||
| 928 | ;; things simple by ensuring we're one of them. | ||
| 929 | (setf (package-desc-kind pkg-desc) | ||
| 930 | (if (length> file-list 1) 'tar 'single)))) | ||
| 931 | ('tar | ||
| 932 | (make-directory package-user-dir t) | ||
| 933 | (let* ((default-directory (file-name-as-directory package-user-dir))) | ||
| 934 | (package-untar-buffer dirname))) | ||
| 935 | ('single | ||
| 936 | (let ((el-file (expand-file-name (format "%s.el" name) pkg-dir))) | ||
| 937 | (make-directory pkg-dir t) | ||
| 938 | (package--write-file-no-coding el-file))) | ||
| 939 | (kind (error "Unknown package kind: %S" kind))) | ||
| 940 | (package--make-autoloads-and-stuff pkg-desc pkg-dir) | ||
| 941 | ;; Update package-alist. | ||
| 942 | (let ((new-desc (package-load-descriptor pkg-dir))) | ||
| 943 | (unless (equal (package-desc-full-name new-desc) | ||
| 944 | (package-desc-full-name pkg-desc)) | ||
| 945 | (error "The retrieved package (`%s') doesn't match what the archive offered (`%s')" | ||
| 946 | (package-desc-full-name new-desc) (package-desc-full-name pkg-desc))) | ||
| 947 | ;; Activation has to be done before compilation, so that if we're | ||
| 948 | ;; upgrading and macros have changed we load the new definitions | ||
| 949 | ;; before compiling. | ||
| 950 | (when (package-activate-1 new-desc :reload :deps) | ||
| 951 | ;; FIXME: Compilation should be done as a separate, optional, step. | ||
| 952 | ;; E.g. for multi-package installs, we should first install all packages | ||
| 953 | ;; and then compile them. | ||
| 954 | (package--compile new-desc) | ||
| 955 | (when package-native-compile | ||
| 956 | (package--native-compile-async new-desc)) | ||
| 957 | ;; After compilation, load again any files loaded by | ||
| 958 | ;; `activate-1', so that we use the byte-compiled definitions. | ||
| 959 | (package--reload-previously-loaded new-desc))) | ||
| 960 | pkg-dir)) | ||
| 961 | |||
| 962 | (defun package-generate-description-file (pkg-desc pkg-file) | ||
| 963 | "Create the foo-pkg.el file PKG-FILE for single-file package PKG-DESC." | ||
| 964 | (let* ((name (package-desc-name pkg-desc))) | ||
| 965 | (let ((print-level nil) | ||
| 966 | (print-quoted t) | ||
| 967 | (print-length nil)) | ||
| 968 | (write-region | ||
| 969 | (concat | ||
| 970 | ";;; Generated package description from " | ||
| 971 | (replace-regexp-in-string "-pkg\\.el\\'" ".el" | ||
| 972 | (file-name-nondirectory pkg-file)) | ||
| 973 | " -*- no-byte-compile: t -*-\n" | ||
| 974 | (prin1-to-string | ||
| 975 | (nconc | ||
| 976 | (list 'define-package | ||
| 977 | (symbol-name name) | ||
| 978 | (package-version-join (package-desc-version pkg-desc)) | ||
| 979 | (package-desc-summary pkg-desc) | ||
| 980 | (let ((requires (package-desc-reqs pkg-desc))) | ||
| 981 | (list 'quote | ||
| 982 | ;; Turn version lists into string form. | ||
| 983 | (mapcar | ||
| 984 | (lambda (elt) | ||
| 985 | (list (car elt) | ||
| 986 | (package-version-join (cadr elt)))) | ||
| 987 | requires)))) | ||
| 988 | (package--alist-to-plist-args | ||
| 989 | (package-desc-extras pkg-desc)))) | ||
| 990 | "\n") | ||
| 991 | nil pkg-file nil 'silent)))) | ||
| 992 | |||
| 993 | ;;;###autoload | ||
| 994 | (defun package-isolate (packages &optional temp-init) | ||
| 995 | "Start an uncustomized Emacs and only load a set of PACKAGES. | ||
| 996 | Interactively, prompt for PACKAGES to load, which should be specified | ||
| 997 | separated by commas. | ||
| 998 | If called from Lisp, PACKAGES should be a list of packages to load. | ||
| 999 | If TEMP-INIT is non-nil, or when invoked with a prefix argument, | ||
| 1000 | the Emacs user directory is set to a temporary directory. | ||
| 1001 | This command is intended for testing Emacs and/or the packages | ||
| 1002 | in a clean environment." | ||
| 1003 | (interactive | ||
| 1004 | (cl-loop for p in (cl-loop for p in (package--alist) append (cdr p)) | ||
| 1005 | unless (package-built-in-p p) | ||
| 1006 | collect (cons (package-desc-full-name p) p) into table | ||
| 1007 | finally return | ||
| 1008 | (list | ||
| 1009 | (cl-loop for c in | ||
| 1010 | (completing-read-multiple | ||
| 1011 | "Packages to isolate: " table | ||
| 1012 | nil t) | ||
| 1013 | collect (alist-get c table nil nil #'string=)) | ||
| 1014 | current-prefix-arg))) | ||
| 1015 | (let* ((name (concat "package-isolate-" | ||
| 1016 | (mapconcat #'package-desc-full-name packages ","))) | ||
| 1017 | (all-packages (delete-consecutive-dups | ||
| 1018 | (sort (append packages (mapcan #'package--dependencies packages)) | ||
| 1019 | (lambda (p0 p1) | ||
| 1020 | (string< (package-desc-name p0) (package-desc-name p1)))))) | ||
| 1021 | initial-scratch-message package-load-list) | ||
| 1022 | (with-temp-buffer | ||
| 1023 | (insert ";; This is an isolated testing environment, with these packages enabled:\n\n") | ||
| 1024 | (dolist (package all-packages) | ||
| 1025 | (push (list (package-desc-name package) | ||
| 1026 | (package-version-join (package-desc-version package))) | ||
| 1027 | package-load-list) | ||
| 1028 | (insert ";; - " (package-desc-full-name package)) | ||
| 1029 | (unless (memq package packages) | ||
| 1030 | (insert " (dependency)")) | ||
| 1031 | (insert "\n")) | ||
| 1032 | (insert "\n") | ||
| 1033 | (setq initial-scratch-message (buffer-string))) | ||
| 1034 | (apply #'start-process (concat "*" name "*") nil | ||
| 1035 | (list (expand-file-name invocation-name invocation-directory) | ||
| 1036 | "--quick" "--debug-init" | ||
| 1037 | "--init-directory" (if temp-init | ||
| 1038 | (make-temp-file name t) | ||
| 1039 | user-emacs-directory) | ||
| 1040 | (format "--eval=%S" | ||
| 1041 | `(progn | ||
| 1042 | (setq initial-scratch-message ,initial-scratch-message) | ||
| 1043 | |||
| 1044 | (require 'package) | ||
| 1045 | ,@(mapcar | ||
| 1046 | (lambda (dir) | ||
| 1047 | `(add-to-list 'package-directory-list ,dir)) | ||
| 1048 | (cons package-user-dir package-directory-list)) | ||
| 1049 | (setq package-load-list ',package-load-list) | ||
| 1050 | (package-activate-all))))))) | ||
| 1051 | |||
| 1052 | (provide 'package-install) | ||
| 1053 | ;;; package-install.el ends here | ||