diff options
Diffstat (limited to 'lisp/package/package-core.el')
| -rw-r--r-- | lisp/package/package-core.el | 927 |
1 files changed, 927 insertions, 0 deletions
diff --git a/lisp/package/package-core.el b/lisp/package/package-core.el new file mode 100644 index 00000000000..83a04402705 --- /dev/null +++ b/lisp/package/package-core.el | |||
| @@ -0,0 +1,927 @@ | |||
| 1 | ;;; package-core.el --- Core of the Emacs Package Manager -*- lexical-binding:t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2007-2025 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Tom Tromey <tromey@redhat.com> | ||
| 6 | ;; Daniel Hackney <dan@haxney.org> | ||
| 7 | ;; Created: 10 Mar 2007 | ||
| 8 | ;; Version: 1.1.0 | ||
| 9 | ;; Keywords: tools | ||
| 10 | ;; Package-Requires: ((tabulated-list "1.0")) | ||
| 11 | |||
| 12 | ;; This file is part of GNU Emacs. | ||
| 13 | |||
| 14 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 15 | ;; it under the terms of the GNU General Public License as published by | ||
| 16 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 17 | ;; (at your option) any later version. | ||
| 18 | |||
| 19 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 22 | ;; GNU General Public License for more details. | ||
| 23 | |||
| 24 | ;; You should have received a copy of the GNU General Public License | ||
| 25 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 26 | |||
| 27 | ;;; Commentary: | ||
| 28 | |||
| 29 | ;; TODO | ||
| 30 | |||
| 31 | ;;; Code: | ||
| 32 | |||
| 33 | (eval-and-compile (require 'cl-lib)) | ||
| 34 | (eval-when-compile (require 'epg)) ;For setf accessors. | ||
| 35 | (eval-when-compile (require 'inline)) ;For `define-inline' | ||
| 36 | |||
| 37 | (defvar package--default-summary "No description available.") | ||
| 38 | |||
| 39 | (defvar package-list-unversioned nil | ||
| 40 | "If non-nil, include packages that don't have a version in `list-packages'.") | ||
| 41 | |||
| 42 | (defvar package-list-unsigned nil | ||
| 43 | "If non-nil, mention in the list which packages were installed without signature.") | ||
| 44 | |||
| 45 | (defvar package--emacs-version-list (version-to-list emacs-version) | ||
| 46 | "The value of variable `emacs-version' as a list.") | ||
| 47 | |||
| 48 | (define-inline package-vc-p (pkg-desc) | ||
| 49 | "Return non-nil if PKG-DESC is a VC package." | ||
| 50 | (inline-letevals (pkg-desc) | ||
| 51 | (inline-quote (eq (package-desc-kind ,pkg-desc) 'vc)))) | ||
| 52 | |||
| 53 | (cl-defstruct (package-desc | ||
| 54 | ;; Rename the default constructor from `make-package-desc'. | ||
| 55 | (:constructor package-desc-create) | ||
| 56 | ;; Has the same interface as the old `define-package', | ||
| 57 | ;; which is still used in the "foo-pkg.el" files. Extra | ||
| 58 | ;; options can be supported by adding additional keys. | ||
| 59 | (:constructor | ||
| 60 | package-desc-from-define | ||
| 61 | (name-string version-string &optional summary requirements | ||
| 62 | &rest rest-plist | ||
| 63 | &aux | ||
| 64 | (name (intern name-string)) | ||
| 65 | (version (if (eq (car-safe version-string) 'vc) | ||
| 66 | (version-to-list (cdr version-string)) | ||
| 67 | (version-to-list version-string))) | ||
| 68 | (reqs (mapcar (lambda (elt) | ||
| 69 | (list (car elt) | ||
| 70 | (version-to-list (cadr elt)))) | ||
| 71 | (if (eq 'quote (car requirements)) | ||
| 72 | (nth 1 requirements) | ||
| 73 | requirements))) | ||
| 74 | (kind (plist-get rest-plist :kind)) | ||
| 75 | (archive (plist-get rest-plist :archive)) | ||
| 76 | (extras (let (alist) | ||
| 77 | (while rest-plist | ||
| 78 | (unless (memq (car rest-plist) '(:kind :archive)) | ||
| 79 | (let ((value (cadr rest-plist))) | ||
| 80 | (when value | ||
| 81 | (push (cons (car rest-plist) | ||
| 82 | (if (eq (car-safe value) 'quote) | ||
| 83 | (cadr value) | ||
| 84 | value)) | ||
| 85 | alist)))) | ||
| 86 | (setq rest-plist (cddr rest-plist))) | ||
| 87 | alist))))) | ||
| 88 | "Structure containing information about an individual package. | ||
| 89 | Slots: | ||
| 90 | |||
| 91 | `name' Name of the package, as a symbol. | ||
| 92 | |||
| 93 | `version' Version of the package, as a version list. | ||
| 94 | |||
| 95 | `summary' Short description of the package, typically taken from | ||
| 96 | the first line of the file. | ||
| 97 | |||
| 98 | `reqs' Requirements of the package. A list of (PACKAGE | ||
| 99 | VERSION-LIST) naming the dependent package and the minimum | ||
| 100 | required version. | ||
| 101 | |||
| 102 | `kind' The distribution format of the package. Currently, it is | ||
| 103 | either `single' or `tar'. | ||
| 104 | |||
| 105 | `archive' The name of the archive (as a string) whence this | ||
| 106 | package came. | ||
| 107 | |||
| 108 | `dir' The directory where the package is installed (if installed), | ||
| 109 | `builtin' if it is built-in, or nil otherwise. | ||
| 110 | |||
| 111 | `extras' Optional alist of additional keyword-value pairs. | ||
| 112 | |||
| 113 | `signed' Flag to indicate that the package is signed by provider." | ||
| 114 | name | ||
| 115 | version | ||
| 116 | (summary package--default-summary) | ||
| 117 | reqs | ||
| 118 | kind | ||
| 119 | archive | ||
| 120 | dir | ||
| 121 | extras | ||
| 122 | signed) | ||
| 123 | |||
| 124 | (cl-defstruct (package--bi-desc | ||
| 125 | (:constructor package-make-builtin (version summary)) | ||
| 126 | (:type vector)) | ||
| 127 | "Package descriptor format used in finder-inf.el and package--builtins." | ||
| 128 | version | ||
| 129 | reqs | ||
| 130 | summary) | ||
| 131 | |||
| 132 | (defun package--from-builtin (bi-desc) | ||
| 133 | "Create a `package-desc' object from BI-DESC. | ||
| 134 | BI-DESC should be a `package--bi-desc' object." | ||
| 135 | (package-desc-create :name (pop bi-desc) | ||
| 136 | :version (package--bi-desc-version bi-desc) | ||
| 137 | :summary (package--bi-desc-summary bi-desc) | ||
| 138 | :dir 'builtin)) | ||
| 139 | |||
| 140 | (defun package-desc--keywords (pkg-desc) | ||
| 141 | "Return keywords of package-desc object PKG-DESC. | ||
| 142 | These keywords come from the foo-pkg.el file, and in general | ||
| 143 | corresponds to the keywords in the \"Keywords\" header of the | ||
| 144 | package." | ||
| 145 | (let ((keywords (cdr (assoc :keywords (package-desc-extras pkg-desc))))) | ||
| 146 | (if (eq (car-safe keywords) 'quote) | ||
| 147 | (nth 1 keywords) | ||
| 148 | keywords))) | ||
| 149 | |||
| 150 | (defun package--read-pkg-desc (kind) | ||
| 151 | "Read a `define-package' form in current buffer. | ||
| 152 | Return the pkg-desc, with desc-kind set to KIND." | ||
| 153 | (goto-char (point-min)) | ||
| 154 | (let* ((pkg-def-parsed (read (current-buffer))) | ||
| 155 | (pkg-desc | ||
| 156 | (when (eq (car pkg-def-parsed) 'define-package) | ||
| 157 | (apply #'package-desc-from-define | ||
| 158 | (append (cdr pkg-def-parsed)))))) | ||
| 159 | (when pkg-desc | ||
| 160 | (setf (package-desc-kind pkg-desc) kind) | ||
| 161 | pkg-desc))) | ||
| 162 | |||
| 163 | (defgroup package nil | ||
| 164 | "Manager for Emacs Lisp packages." | ||
| 165 | :group 'applications | ||
| 166 | :version "24.1") | ||
| 167 | |||
| 168 | |||
| 169 | ;;; Customization options | ||
| 170 | |||
| 171 | ;;;###autoload | ||
| 172 | (defcustom package-enable-at-startup t | ||
| 173 | "Whether to make installed packages available when Emacs starts. | ||
| 174 | If non-nil, packages are made available before reading the init | ||
| 175 | file (but after reading the early init file). This means that if | ||
| 176 | you wish to set this variable, you must do so in the early init | ||
| 177 | file. Regardless of the value of this variable, packages are not | ||
| 178 | made available if `user-init-file' is nil (e.g. Emacs was started | ||
| 179 | with \"-q\"). | ||
| 180 | |||
| 181 | Even if the value is nil, you can type \\[package-initialize] to | ||
| 182 | make installed packages available at any time, or you can | ||
| 183 | call (package-activate-all) in your init-file. | ||
| 184 | |||
| 185 | Note that this variable must be set to a non-default value in | ||
| 186 | your early-init file, as the variable's value is used before | ||
| 187 | loading the regular init file. Therefore, if you customize it | ||
| 188 | via Customize, you should save your customized setting into | ||
| 189 | your `early-init-file'." | ||
| 190 | :type 'boolean | ||
| 191 | :version "24.1") | ||
| 192 | |||
| 193 | (defcustom package-load-list '(all) | ||
| 194 | "List of packages for `package-activate-all' to make available. | ||
| 195 | Each element in this list should be a list (NAME VERSION), or the | ||
| 196 | symbol `all'. The symbol `all' says to make available the latest | ||
| 197 | installed versions of all packages not specified by other | ||
| 198 | elements. | ||
| 199 | |||
| 200 | For an element (NAME VERSION), NAME is a package name (a symbol). | ||
| 201 | VERSION should be t, a string, or nil. | ||
| 202 | If VERSION is t, the most recent version is made available. | ||
| 203 | If VERSION is a string, only that version is ever made available. | ||
| 204 | Any other version, even if newer, is silently ignored. | ||
| 205 | Hence, the package is \"held\" at that version. | ||
| 206 | If VERSION is nil, the package is not made available (it is \"disabled\")." | ||
| 207 | :type '(repeat (choice (const all) | ||
| 208 | (list :tag "Specific package" | ||
| 209 | (symbol :tag "Package name") | ||
| 210 | (choice :tag "Version" | ||
| 211 | (const :tag "disable" nil) | ||
| 212 | (const :tag "most recent" t) | ||
| 213 | (string :tag "specific version"))))) | ||
| 214 | :risky t | ||
| 215 | :version "24.1") | ||
| 216 | |||
| 217 | (defcustom package-pinned-packages nil | ||
| 218 | "An alist of packages that are pinned to specific archives. | ||
| 219 | This can be useful if you have multiple package archives enabled, | ||
| 220 | and want to control which archive a given package gets installed from. | ||
| 221 | |||
| 222 | Each element of the alist has the form (PACKAGE . ARCHIVE), where: | ||
| 223 | PACKAGE is a symbol representing a package | ||
| 224 | ARCHIVE is a string representing an archive (it should be the car of | ||
| 225 | an element in `package-archives', e.g. \"gnu\"). | ||
| 226 | |||
| 227 | Adding an entry to this variable means that only ARCHIVE will be | ||
| 228 | considered as a source for PACKAGE. If other archives provide PACKAGE, | ||
| 229 | they are ignored (for this package). If ARCHIVE does not contain PACKAGE, | ||
| 230 | the package will be unavailable." | ||
| 231 | :type '(alist :key-type (symbol :tag "Package") | ||
| 232 | :value-type (string :tag "Archive name")) | ||
| 233 | ;; This could prevent you from receiving updates for a package, | ||
| 234 | ;; via an entry (PACKAGE . NON-EXISTING). Which could be an issue | ||
| 235 | ;; if PACKAGE has a known vulnerability that is fixed in newer versions. | ||
| 236 | :risky t | ||
| 237 | :version "24.4") | ||
| 238 | |||
| 239 | ;;;###autoload | ||
| 240 | (defcustom package-user-dir (locate-user-emacs-file "elpa") | ||
| 241 | "Directory containing the user's Emacs Lisp packages. | ||
| 242 | The directory name should be absolute. | ||
| 243 | Apart from this directory, Emacs also looks for system-wide | ||
| 244 | packages in `package-directory-list'." | ||
| 245 | :type 'directory | ||
| 246 | :initialize #'custom-initialize-delay | ||
| 247 | :risky t | ||
| 248 | :group 'applications | ||
| 249 | :version "24.1") | ||
| 250 | |||
| 251 | ;;;###autoload | ||
| 252 | (defcustom package-directory-list | ||
| 253 | ;; Defaults are subdirs named "elpa" in the site-lisp dirs. | ||
| 254 | (let (result) | ||
| 255 | (dolist (f load-path) | ||
| 256 | (and (stringp f) | ||
| 257 | (equal (file-name-nondirectory f) "site-lisp") | ||
| 258 | (push (expand-file-name "elpa" f) result))) | ||
| 259 | (nreverse result)) | ||
| 260 | "List of additional directories containing Emacs Lisp packages. | ||
| 261 | Each directory name should be absolute. | ||
| 262 | |||
| 263 | These directories contain packages intended for system-wide; in | ||
| 264 | contrast, `package-user-dir' contains packages for personal use." | ||
| 265 | :type '(repeat directory) | ||
| 266 | :initialize #'custom-initialize-delay | ||
| 267 | :group 'applications | ||
| 268 | :risky t | ||
| 269 | :version "24.1") | ||
| 270 | |||
| 271 | (defcustom package-selected-packages nil | ||
| 272 | "Store here packages installed explicitly by user. | ||
| 273 | This variable is fed automatically by Emacs when installing a new package. | ||
| 274 | This variable is used by `package-autoremove' to decide | ||
| 275 | which packages are no longer needed. | ||
| 276 | You can use it to (re)install packages on other machines | ||
| 277 | by running `package-install-selected-packages'. | ||
| 278 | |||
| 279 | To check if a package is contained in this list here, use | ||
| 280 | `package--user-selected-p', as it may populate the variable with | ||
| 281 | a sane initial value." | ||
| 282 | :version "25.1" | ||
| 283 | :type '(repeat symbol)) | ||
| 284 | |||
| 285 | ;; Pseudo fields. | ||
| 286 | (defun package-version-join (vlist) | ||
| 287 | "Return the version string corresponding to the list VLIST. | ||
| 288 | This is, approximately, the inverse of `version-to-list'. | ||
| 289 | \(Actually, it returns only one of the possible inverses, since | ||
| 290 | `version-to-list' is a many-to-one operation.)" | ||
| 291 | (if (null vlist) | ||
| 292 | "" | ||
| 293 | (let ((str-list (list "." (int-to-string (car vlist))))) | ||
| 294 | (dolist (num (cdr vlist)) | ||
| 295 | (cond | ||
| 296 | ((>= num 0) | ||
| 297 | (push (int-to-string num) str-list) | ||
| 298 | (push "." str-list)) | ||
| 299 | ((< num -4) | ||
| 300 | (error "Invalid version list `%s'" vlist)) | ||
| 301 | (t | ||
| 302 | ;; pre, or beta, or alpha | ||
| 303 | (cond ((equal "." (car str-list)) | ||
| 304 | (pop str-list)) | ||
| 305 | ((not (string-match "[0-9]+" (car str-list))) | ||
| 306 | (error "Invalid version list `%s'" vlist))) | ||
| 307 | (push (cond ((= num -1) "pre") | ||
| 308 | ((= num -2) "beta") | ||
| 309 | ((= num -3) "alpha") | ||
| 310 | ((= num -4) "snapshot")) | ||
| 311 | str-list)))) | ||
| 312 | (if (equal "." (car str-list)) | ||
| 313 | (pop str-list)) | ||
| 314 | (apply #'concat (nreverse str-list))))) | ||
| 315 | |||
| 316 | |||
| 317 | |||
| 318 | ;;; Installed packages | ||
| 319 | ;; The following variables store information about packages present in | ||
| 320 | ;; the system. The most important of these is `package-alist'. The | ||
| 321 | ;; command `package-activate-all' is also closely related to this | ||
| 322 | ;; section. | ||
| 323 | |||
| 324 | (defvar package--builtins nil | ||
| 325 | "Alist of built-in packages. | ||
| 326 | The actual value is initialized by loading the library | ||
| 327 | `finder-inf'; this is not done until it is needed, e.g. by the | ||
| 328 | function `package-built-in-p'. | ||
| 329 | |||
| 330 | Each element has the form (PKG . PACKAGE-BI-DESC), where PKG is a package | ||
| 331 | name (a symbol) and DESC is a `package--bi-desc' structure.") | ||
| 332 | (put 'package--builtins 'risky-local-variable t) | ||
| 333 | |||
| 334 | (defvar package-alist nil | ||
| 335 | "Alist of all packages available for activation. | ||
| 336 | Each element has the form (PKG . DESCS), where PKG is a package | ||
| 337 | name (a symbol) and DESCS is a non-empty list of `package-desc' | ||
| 338 | structures, sorted by decreasing versions. | ||
| 339 | |||
| 340 | This variable is set automatically by `package-load-descriptor', | ||
| 341 | called via `package-activate-all'. To change which packages are | ||
| 342 | loaded and/or activated, customize `package-load-list'.") | ||
| 343 | (put 'package-alist 'risky-local-variable t) | ||
| 344 | |||
| 345 | ;;;; Public interfaces for accessing built-in package info | ||
| 346 | |||
| 347 | (defun package-versioned-builtin-packages () | ||
| 348 | "Return a list of all the versioned built-in packages. | ||
| 349 | The return value is a list of names of built-in packages represented as | ||
| 350 | symbols." | ||
| 351 | (mapcar #'car package--builtin-versions)) | ||
| 352 | |||
| 353 | (defun package-builtin-package-version (package) | ||
| 354 | "Return the version of a built-in PACKAGE given by its symbol. | ||
| 355 | The return value is a list of integers representing the version of | ||
| 356 | PACKAGE, in the format returned by `version-to-list', or nil if the | ||
| 357 | package is built-in but has no version or is not a built-in package." | ||
| 358 | (alist-get package package--builtin-versions)) | ||
| 359 | |||
| 360 | ;;;###autoload | ||
| 361 | (defvar package-activated-list nil | ||
| 362 | ;; FIXME: This should implicitly include all builtin packages. | ||
| 363 | "List of the names of currently activated packages.") | ||
| 364 | (put 'package-activated-list 'risky-local-variable t) | ||
| 365 | |||
| 366 | ;;;; Populating `package-alist'. | ||
| 367 | |||
| 368 | ;; The following functions are called on each installed package by | ||
| 369 | ;; `package-load-all-descriptors', which ultimately populates the | ||
| 370 | ;; `package-alist' variable. | ||
| 371 | |||
| 372 | (defun package-process-define-package (exp) | ||
| 373 | "Process define-package expression EXP and push it to `package-alist'. | ||
| 374 | EXP should be a form read from a foo-pkg.el file. | ||
| 375 | Convert EXP into a `package-desc' object using the | ||
| 376 | `package-desc-from-define' constructor before pushing it to | ||
| 377 | `package-alist'. | ||
| 378 | |||
| 379 | If there already exists a package by the same name in | ||
| 380 | `package-alist', insert this object there such that the packages | ||
| 381 | are sorted with the highest version first." | ||
| 382 | (when (eq (car-safe exp) 'define-package) | ||
| 383 | (let* ((new-pkg-desc (apply #'package-desc-from-define (cdr exp))) | ||
| 384 | (name (package-desc-name new-pkg-desc)) | ||
| 385 | (version (package-desc-version new-pkg-desc)) | ||
| 386 | (old-pkgs (assq name package-alist))) | ||
| 387 | (if (null old-pkgs) | ||
| 388 | ;; If there's no old package, just add this to `package-alist'. | ||
| 389 | (push (list name new-pkg-desc) package-alist) | ||
| 390 | ;; If there is, insert the new package at the right place in the list. | ||
| 391 | (while | ||
| 392 | (if (and (cdr old-pkgs) | ||
| 393 | (version-list-< version | ||
| 394 | (package-desc-version (cadr old-pkgs)))) | ||
| 395 | (setq old-pkgs (cdr old-pkgs)) | ||
| 396 | (push new-pkg-desc (cdr old-pkgs)) | ||
| 397 | nil))) | ||
| 398 | new-pkg-desc))) | ||
| 399 | |||
| 400 | (defun package-load-descriptor (pkg-dir) | ||
| 401 | "Load the package description file in directory PKG-DIR. | ||
| 402 | Create a new `package-desc' object, add it to `package-alist' and | ||
| 403 | return it." | ||
| 404 | (let ((pkg-file (expand-file-name (package--description-file pkg-dir) | ||
| 405 | pkg-dir)) | ||
| 406 | (signed-file (concat pkg-dir ".signed"))) | ||
| 407 | (when (file-exists-p pkg-file) | ||
| 408 | (with-temp-buffer | ||
| 409 | (insert-file-contents pkg-file) | ||
| 410 | (goto-char (point-min)) | ||
| 411 | (let ((pkg-desc (or (package-process-define-package | ||
| 412 | (read (current-buffer))) | ||
| 413 | (error "Can't find define-package in %s" pkg-file)))) | ||
| 414 | (setf (package-desc-dir pkg-desc) pkg-dir) | ||
| 415 | (if (file-exists-p signed-file) | ||
| 416 | (setf (package-desc-signed pkg-desc) t)) | ||
| 417 | pkg-desc))))) | ||
| 418 | |||
| 419 | (defun package-load-all-descriptors () | ||
| 420 | "Load descriptors for installed Emacs Lisp packages. | ||
| 421 | This looks for package subdirectories in `package-user-dir' and | ||
| 422 | `package-directory-list'. The variable `package-load-list' | ||
| 423 | controls which package subdirectories may be loaded. | ||
| 424 | |||
| 425 | In each valid package subdirectory, this function loads the | ||
| 426 | description file containing a call to `define-package', which | ||
| 427 | updates `package-alist'." | ||
| 428 | (dolist (dir (cons package-user-dir package-directory-list)) | ||
| 429 | (when (file-directory-p dir) | ||
| 430 | (dolist (pkg-dir (directory-files dir t "\\`[^.]")) | ||
| 431 | (when (file-directory-p pkg-dir) | ||
| 432 | (package-load-descriptor pkg-dir)))))) | ||
| 433 | |||
| 434 | (defun package--alist () | ||
| 435 | "Return `package-alist', after computing it if needed." | ||
| 436 | (or package-alist | ||
| 437 | (progn (package-load-all-descriptors) | ||
| 438 | package-alist))) | ||
| 439 | |||
| 440 | |||
| 441 | ;;; Package activation | ||
| 442 | ;; Section for functions used by `package-activate', which see. | ||
| 443 | |||
| 444 | (defun package-disabled-p (pkg-name version) | ||
| 445 | "Return whether PKG-NAME at VERSION can be activated. | ||
| 446 | The decision is made according to `package-load-list'. | ||
| 447 | Return nil if the package can be activated. | ||
| 448 | Return t if the package is completely disabled. | ||
| 449 | Return the max version (as a string) if the package is held at a lower version." | ||
| 450 | (let ((force (assq pkg-name package-load-list))) | ||
| 451 | (cond ((null force) (not (memq 'all package-load-list))) | ||
| 452 | ((null (setq force (cadr force))) t) ; disabled | ||
| 453 | ((eq force t) nil) | ||
| 454 | ((stringp force) ; held | ||
| 455 | (unless (version-list-= version (version-to-list force)) | ||
| 456 | force)) | ||
| 457 | (t (error "Invalid element in `package-load-list'"))))) | ||
| 458 | |||
| 459 | (defun package-built-in-p (package &optional min-version) | ||
| 460 | "Return non-nil if PACKAGE is built-in to Emacs. | ||
| 461 | Optional arg MIN-VERSION, if non-nil, should be a version list | ||
| 462 | specifying the minimum acceptable version." | ||
| 463 | (if (package-desc-p package) ;; was built-in and then was converted | ||
| 464 | (eq 'builtin (package-desc-dir package)) | ||
| 465 | (let ((bi (assq package package--builtin-versions))) | ||
| 466 | (cond | ||
| 467 | (bi (version-list-<= min-version (cdr bi))) | ||
| 468 | ((remove 0 min-version) nil) | ||
| 469 | (t | ||
| 470 | (require 'finder-inf nil t) ; For `package--builtins'. | ||
| 471 | (assq package package--builtins)))))) | ||
| 472 | |||
| 473 | (defun package--active-built-in-p (package) | ||
| 474 | "Return non-nil if the built-in version of PACKAGE is used. | ||
| 475 | If the built-in version of PACKAGE is used and PACKAGE is | ||
| 476 | also available for installation from an archive, it is an | ||
| 477 | indication that PACKAGE was never upgraded to any newer | ||
| 478 | version from the archive." | ||
| 479 | (and (not (assq (cond | ||
| 480 | ((package-desc-p package) | ||
| 481 | (package-desc-name package)) | ||
| 482 | ((stringp package) (intern package)) | ||
| 483 | ((symbolp package) package) | ||
| 484 | ((error "Unknown package format: %S" package))) | ||
| 485 | (package--alist))) | ||
| 486 | (package-built-in-p package))) | ||
| 487 | |||
| 488 | (defun package--autoloads-file-name (pkg-desc) | ||
| 489 | "Return the absolute name of the autoloads file, sans extension. | ||
| 490 | PKG-DESC is a `package-desc' object." | ||
| 491 | (expand-file-name | ||
| 492 | (format "%s-autoloads" (package-desc-name pkg-desc)) | ||
| 493 | (package-desc-dir pkg-desc))) | ||
| 494 | |||
| 495 | (defvar Info-directory-list) | ||
| 496 | (declare-function info-initialize "info" ()) | ||
| 497 | |||
| 498 | (defvar package--quickstart-pkgs t | ||
| 499 | "If set to a list, we're computing the set of pkgs to activate.") | ||
| 500 | |||
| 501 | (defsubst package--library-stem (file) | ||
| 502 | (catch 'done | ||
| 503 | (let (result) | ||
| 504 | (dolist (suffix (get-load-suffixes) file) | ||
| 505 | (setq result (string-trim file nil suffix)) | ||
| 506 | (unless (equal file result) | ||
| 507 | (throw 'done result)))))) | ||
| 508 | |||
| 509 | (defun package--reload-previously-loaded (pkg-desc &optional warn) | ||
| 510 | "Force reimportation of files in PKG-DESC already present in `load-history'. | ||
| 511 | New editions of files contain macro definitions and | ||
| 512 | redefinitions, the overlooking of which would cause | ||
| 513 | byte-compilation of the new package to fail. | ||
| 514 | If WARN is a string, display a warning (using WARN as a format string) | ||
| 515 | before reloading the files. WARN must have two %-sequences | ||
| 516 | corresponding to package name (a symbol) and a list of files loaded (as | ||
| 517 | sexps)." | ||
| 518 | (with-demoted-errors "Error in package--load-files-for-activation: %s" | ||
| 519 | (let* (result | ||
| 520 | (dir (package-desc-dir pkg-desc)) | ||
| 521 | ;; A previous implementation would skip `dir' itself. | ||
| 522 | ;; However, in normal use reloading from the same directory | ||
| 523 | ;; never happens anyway, while in certain cases external to | ||
| 524 | ;; Emacs a package in the same directory not necessary | ||
| 525 | ;; stays byte-identical, e.g. during development. Just | ||
| 526 | ;; don't special-case `dir'. | ||
| 527 | (effective-path (or (bound-and-true-p find-library-source-path) | ||
| 528 | load-path)) | ||
| 529 | (files (directory-files-recursively dir "\\`[^\\.].*\\.el\\'")) | ||
| 530 | (history (mapcar #'file-truename | ||
| 531 | (cl-remove-if-not #'stringp | ||
| 532 | (mapcar #'car load-history))))) | ||
| 533 | (dolist (file files) | ||
| 534 | (when-let* ((library (package--library-stem | ||
| 535 | (file-relative-name file dir))) | ||
| 536 | (canonical (locate-library library nil effective-path)) | ||
| 537 | (truename (file-truename canonical)) | ||
| 538 | ;; Normally, all files in a package are compiled by | ||
| 539 | ;; now, but don't assume that. E.g. different | ||
| 540 | ;; versions can add or remove `no-byte-compile'. | ||
| 541 | (altname (if (string-suffix-p ".el" truename) | ||
| 542 | (replace-regexp-in-string | ||
| 543 | "\\.el\\'" ".elc" truename t) | ||
| 544 | (replace-regexp-in-string | ||
| 545 | "\\.elc\\'" ".el" truename t))) | ||
| 546 | (found (or (member truename history) | ||
| 547 | (and (not (string= altname truename)) | ||
| 548 | (member altname history)))) | ||
| 549 | (recent-index (length found))) | ||
| 550 | (unless (equal (file-name-base library) | ||
| 551 | (format "%s-autoloads" (package-desc-name pkg-desc))) | ||
| 552 | (push (cons (expand-file-name library dir) recent-index) result)))) | ||
| 553 | (when (and result warn) | ||
| 554 | (display-warning 'package | ||
| 555 | (format warn (package-desc-name pkg-desc) | ||
| 556 | (mapcar #'car result)))) | ||
| 557 | (mapc (lambda (c) (load (car c) nil t)) | ||
| 558 | (sort result (lambda (x y) (< (cdr x) (cdr y)))))))) | ||
| 559 | |||
| 560 | (defun package-desc-full-name (pkg-desc) | ||
| 561 | "Return full name of package-desc object PKG-DESC. | ||
| 562 | This is the name of the package with its version appended." | ||
| 563 | (if (package-vc-p pkg-desc) | ||
| 564 | (symbol-name (package-desc-name pkg-desc)) | ||
| 565 | (format "%s-%s" | ||
| 566 | (package-desc-name pkg-desc) | ||
| 567 | (package-version-join (package-desc-version pkg-desc))))) | ||
| 568 | |||
| 569 | (defun package-activate-1 (pkg-desc &optional reload deps) | ||
| 570 | "Activate package given by PKG-DESC, even if it was already active. | ||
| 571 | If DEPS is non-nil, also activate its dependencies (unless they | ||
| 572 | are already activated). | ||
| 573 | If RELOAD is non-nil, also `load' any files inside the package which | ||
| 574 | correspond to previously loaded files." | ||
| 575 | (let* ((name (package-desc-name pkg-desc)) | ||
| 576 | (pkg-dir (package-desc-dir pkg-desc))) | ||
| 577 | (unless pkg-dir | ||
| 578 | (error "Internal error: unable to find directory for `%s'" | ||
| 579 | (package-desc-full-name pkg-desc))) | ||
| 580 | (catch 'exit | ||
| 581 | ;; Activate its dependencies recursively. | ||
| 582 | ;; FIXME: This doesn't check whether the activated version is the | ||
| 583 | ;; required version. | ||
| 584 | (when deps | ||
| 585 | (dolist (req (package-desc-reqs pkg-desc)) | ||
| 586 | (unless (package-activate (car req)) | ||
| 587 | (message "Unable to activate package `%s'.\nRequired package `%s-%s' is unavailable" | ||
| 588 | name (car req) (package-version-join (cadr req))) | ||
| 589 | (throw 'exit nil)))) | ||
| 590 | (if (listp package--quickstart-pkgs) | ||
| 591 | ;; We're only collecting the set of packages to activate! | ||
| 592 | (push pkg-desc package--quickstart-pkgs) | ||
| 593 | (when (or reload (assq name package--builtin-versions)) | ||
| 594 | (package--reload-previously-loaded | ||
| 595 | pkg-desc (unless reload | ||
| 596 | "Package %S is activated too late. | ||
| 597 | The following files have already been loaded: %S"))) | ||
| 598 | (with-demoted-errors "Error loading autoloads: %s" | ||
| 599 | (load (package--autoloads-file-name pkg-desc) nil t))) | ||
| 600 | ;; Add info node. | ||
| 601 | (when (file-exists-p (expand-file-name "dir" pkg-dir)) | ||
| 602 | ;; FIXME: not the friendliest, but simple. | ||
| 603 | (require 'info) | ||
| 604 | (info-initialize) | ||
| 605 | (add-to-list 'Info-directory-list pkg-dir)) | ||
| 606 | (push name package-activated-list) | ||
| 607 | ;; Don't return nil. | ||
| 608 | t))) | ||
| 609 | |||
| 610 | ;;;; `package-activate' | ||
| 611 | |||
| 612 | (defun package--get-activatable-pkg (pkg-name) | ||
| 613 | ;; Is "activatable" a word? | ||
| 614 | (let ((pkg-descs (cdr (assq pkg-name package-alist)))) | ||
| 615 | ;; Check if PACKAGE is available in `package-alist'. | ||
| 616 | (while | ||
| 617 | (when pkg-descs | ||
| 618 | (let ((available-version (package-desc-version (car pkg-descs)))) | ||
| 619 | (or (package-disabled-p pkg-name available-version) | ||
| 620 | ;; Prefer a builtin package. | ||
| 621 | (package-built-in-p pkg-name available-version)))) | ||
| 622 | (setq pkg-descs (cdr pkg-descs))) | ||
| 623 | (car pkg-descs))) | ||
| 624 | |||
| 625 | (defvar package--initialized nil | ||
| 626 | "Non-nil if `package-initialize' has been run.") | ||
| 627 | |||
| 628 | ;; This function activates a newer version of a package if an older | ||
| 629 | ;; one was already activated. It also loads a features of this | ||
| 630 | ;; package which were already loaded. | ||
| 631 | (defun package-activate (package &optional force) | ||
| 632 | "Activate the package named PACKAGE. | ||
| 633 | If FORCE is true, (re-)activate it if it's already activated. | ||
| 634 | Newer versions are always activated, regardless of FORCE." | ||
| 635 | (let ((pkg-desc (package--get-activatable-pkg package))) | ||
| 636 | (cond | ||
| 637 | ;; If no such package is found, maybe it's built-in. | ||
| 638 | ((null pkg-desc) | ||
| 639 | (package-built-in-p package)) | ||
| 640 | ;; If the package is already activated, just return t. | ||
| 641 | ((and (memq package package-activated-list) (not force)) | ||
| 642 | t) | ||
| 643 | ;; Otherwise, proceed with activation. | ||
| 644 | (t (package-activate-1 pkg-desc nil 'deps))))) | ||
| 645 | |||
| 646 | |||
| 647 | ;;; Installation -- Local operations | ||
| 648 | ;; This section contains a variety of features regarding installing a | ||
| 649 | ;; package to/from disk. This includes autoload generation, | ||
| 650 | ;; unpacking, compiling, as well as defining a package from the | ||
| 651 | ;; current buffer. | ||
| 652 | |||
| 653 | ;;;; Unpacking | ||
| 654 | |||
| 655 | ;;;###autoload | ||
| 656 | (defvar package--activated nil | ||
| 657 | "Non-nil if `package-activate-all' has been run.") | ||
| 658 | |||
| 659 | (declare-function package-read-all-archive-contents "package-elpa" ()) | ||
| 660 | |||
| 661 | (defvar package--compatibility-table nil | ||
| 662 | "Hash table connecting package names to their compatibility. | ||
| 663 | Each key is a symbol, the name of a package. | ||
| 664 | |||
| 665 | The value is either nil, representing an incompatible package, or | ||
| 666 | a version list, representing the highest compatible version of | ||
| 667 | that package which is available. | ||
| 668 | |||
| 669 | A package is considered incompatible if it requires an Emacs | ||
| 670 | version higher than the one being used. To check for package | ||
| 671 | \(in)compatibility, don't read this table directly, use | ||
| 672 | `package--incompatible-p' which also checks dependencies.") | ||
| 673 | |||
| 674 | (defun package--add-to-compatibility-table (pkg) | ||
| 675 | "If PKG is compatible (without dependencies), add to the compatibility table. | ||
| 676 | PKG is a package-desc object. | ||
| 677 | Only adds if its version is higher than what's already stored in | ||
| 678 | the table." | ||
| 679 | (unless (package--incompatible-p pkg 'shallow) | ||
| 680 | (let* ((name (package-desc-name pkg)) | ||
| 681 | (version (or (package-desc-version pkg) '(0))) | ||
| 682 | (table-version (gethash name package--compatibility-table))) | ||
| 683 | (when (or (not table-version) | ||
| 684 | (version-list-< table-version version)) | ||
| 685 | (puthash name version package--compatibility-table))))) | ||
| 686 | |||
| 687 | (defun package--mapc (function &optional packages) | ||
| 688 | "Call FUNCTION for all known PACKAGES. | ||
| 689 | PACKAGES can be nil or t, which means to display all known | ||
| 690 | packages, or a list of packages. | ||
| 691 | |||
| 692 | Built-in packages are converted with `package--from-builtin'." | ||
| 693 | (unless packages (setq packages t)) | ||
| 694 | (let (name) | ||
| 695 | ;; Installed packages: | ||
| 696 | (dolist (elt package-alist) | ||
| 697 | (setq name (car elt)) | ||
| 698 | (when (or (eq packages t) (memq name packages)) | ||
| 699 | (mapc function (cdr elt)))) | ||
| 700 | |||
| 701 | ;; Built-in packages: | ||
| 702 | (dolist (elt package--builtins) | ||
| 703 | (setq name (car elt)) | ||
| 704 | (when (and (not (eq name 'emacs)) ; Hide the `emacs' package. | ||
| 705 | (or package-list-unversioned | ||
| 706 | (package--bi-desc-version (cdr elt))) | ||
| 707 | (or (eq packages t) (memq name packages))) | ||
| 708 | (funcall function (package--from-builtin elt)))) | ||
| 709 | |||
| 710 | ;; Available and disabled packages: | ||
| 711 | (dolist (elt (bound-and-true-p package-archive-contents)) | ||
| 712 | (setq name (car elt)) | ||
| 713 | (when (or (eq packages t) (memq name packages)) | ||
| 714 | (dolist (pkg (cdr elt)) | ||
| 715 | ;; Hide obsolete packages. | ||
| 716 | (unless (package-installed-p (package-desc-name pkg) | ||
| 717 | (package-desc-version pkg)) | ||
| 718 | (funcall function pkg))))))) | ||
| 719 | |||
| 720 | (defun package--build-compatibility-table () | ||
| 721 | "Build `package--compatibility-table' with `package--mapc'." | ||
| 722 | ;; Initialize the list of built-ins. | ||
| 723 | (require 'finder-inf nil t) | ||
| 724 | ;; Build compat table. | ||
| 725 | (setq package--compatibility-table (make-hash-table :test 'eq)) | ||
| 726 | (package--mapc #'package--add-to-compatibility-table)) | ||
| 727 | |||
| 728 | ;;;###autoload | ||
| 729 | (defun package-initialize (&optional no-activate) | ||
| 730 | "Load Emacs Lisp packages, and activate them. | ||
| 731 | The variable `package-load-list' controls which packages to load. | ||
| 732 | If optional arg NO-ACTIVATE is non-nil, don't activate packages. | ||
| 733 | |||
| 734 | It is not necessary to adjust `load-path' or `require' the | ||
| 735 | individual packages after calling `package-initialize' -- this is | ||
| 736 | taken care of by `package-initialize'. | ||
| 737 | |||
| 738 | If `package-initialize' is called twice during Emacs startup, | ||
| 739 | signal a warning, since this is a bad idea except in highly | ||
| 740 | advanced use cases. To suppress the warning, remove the | ||
| 741 | superfluous call to `package-initialize' from your init-file. If | ||
| 742 | you have code which must run before `package-initialize', put | ||
| 743 | that code in the early init-file." | ||
| 744 | (interactive) | ||
| 745 | (when (and package--initialized (not after-init-time)) | ||
| 746 | (lwarn '(package reinitialization) :warning | ||
| 747 | "Unnecessary call to `package-initialize' in init file")) | ||
| 748 | (setq package-alist nil) | ||
| 749 | (package-load-all-descriptors) | ||
| 750 | (require 'package) | ||
| 751 | (package-read-all-archive-contents) | ||
| 752 | (setq package--initialized t) | ||
| 753 | (unless no-activate | ||
| 754 | (package-activate-all)) | ||
| 755 | ;; This uses `package--mapc' so it must be called after | ||
| 756 | ;; `package--initialized' is t. | ||
| 757 | (package--build-compatibility-table)) | ||
| 758 | |||
| 759 | ;;;###autoload | ||
| 760 | (progn ;; Make the function usable without loading `package.el'. | ||
| 761 | (defun package-activate-all () | ||
| 762 | "Activate all installed packages. | ||
| 763 | The variable `package-load-list' controls which packages to load." | ||
| 764 | (setq package--activated t) | ||
| 765 | (let* ((elc (concat package-quickstart-file "c")) | ||
| 766 | (qs (if (file-readable-p elc) elc | ||
| 767 | (if (file-readable-p package-quickstart-file) | ||
| 768 | package-quickstart-file)))) | ||
| 769 | ;; The quickstart file presumes that it has a blank slate, | ||
| 770 | ;; so don't use it if we already activated some packages. | ||
| 771 | (or (and qs (not (bound-and-true-p package-activated-list)) | ||
| 772 | ;; Skip `load-source-file-function' which would slow us down by | ||
| 773 | ;; a factor 2 when loading the .el file (this assumes we were | ||
| 774 | ;; careful to save this file so it doesn't need any decoding). | ||
| 775 | (with-demoted-errors "Error during quickstart: %S" | ||
| 776 | (let ((load-source-file-function nil)) | ||
| 777 | (unless (boundp 'package-activated-list) | ||
| 778 | (setq package-activated-list nil)) | ||
| 779 | (load qs nil 'nomessage) | ||
| 780 | t))) | ||
| 781 | (progn | ||
| 782 | (require 'package) | ||
| 783 | ;; Silence the "unknown function" warning when this is compiled | ||
| 784 | ;; inside `loaddefs.el'. | ||
| 785 | ;; FIXME: We use `with-no-warnings' because the effect of | ||
| 786 | ;; `declare-function' is currently not scoped, so if we use | ||
| 787 | ;; it here, we end up with a redefinition warning instead :-) | ||
| 788 | (with-no-warnings | ||
| 789 | (package--activate-all))))))) | ||
| 790 | |||
| 791 | (defun package--activate-all () | ||
| 792 | (dolist (elt (package--alist)) | ||
| 793 | (condition-case err | ||
| 794 | (package-activate (car elt)) | ||
| 795 | ;; Don't let failure of activation of a package arbitrarily stop | ||
| 796 | ;; activation of further packages. | ||
| 797 | (error (message "%s" (error-message-string err)))))) | ||
| 798 | |||
| 799 | (defun package-strip-rcs-id (str) | ||
| 800 | "Strip RCS version ID from the version string STR. | ||
| 801 | If the result looks like a dotted numeric version, return it. | ||
| 802 | Otherwise return nil." | ||
| 803 | (when str | ||
| 804 | (when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str) | ||
| 805 | (setq str (substring str (match-end 0)))) | ||
| 806 | (let ((l (version-to-list str))) | ||
| 807 | ;; Don't return `str' but (package-version-join (version-to-list str)) | ||
| 808 | ;; to make sure we use a "canonical name"! | ||
| 809 | (if l (package-version-join l))))) | ||
| 810 | |||
| 811 | (defun package--incompatible-p (pkg &optional shallow) | ||
| 812 | "Return non-nil if PKG has no chance of being installable. | ||
| 813 | PKG is a `package-desc' object. | ||
| 814 | |||
| 815 | If SHALLOW is non-nil, this only checks if PKG depends on a | ||
| 816 | higher `emacs-version' than the one being used. Otherwise, also | ||
| 817 | checks the viability of dependencies, according to | ||
| 818 | `package--compatibility-table'. | ||
| 819 | |||
| 820 | If PKG requires an incompatible Emacs version, the return value | ||
| 821 | is this version (as a string). | ||
| 822 | If PKG requires incompatible packages, the return value is a list | ||
| 823 | of these dependencies, similar to the list returned by | ||
| 824 | `package-desc-reqs'." | ||
| 825 | (let* ((reqs (package-desc-reqs pkg)) | ||
| 826 | (version (cadr (assq 'emacs reqs)))) | ||
| 827 | (if (and version (version-list-< package--emacs-version-list version)) | ||
| 828 | (package-version-join version) | ||
| 829 | (unless shallow | ||
| 830 | (let (out) | ||
| 831 | (dolist (dep (package-desc-reqs pkg) out) | ||
| 832 | (let ((dep-name (car dep))) | ||
| 833 | (unless (eq 'emacs dep-name) | ||
| 834 | (let ((cv (gethash dep-name package--compatibility-table))) | ||
| 835 | (when (version-list-< (or cv '(0)) (or (cadr dep) '(0))) | ||
| 836 | (push dep out))))))))))) | ||
| 837 | |||
| 838 | (defun package--find-non-dependencies () | ||
| 839 | "Return a list of installed packages which are not dependencies. | ||
| 840 | Finds all packages in `package-alist' which are not dependencies | ||
| 841 | of any other packages. | ||
| 842 | Used to populate `package-selected-packages'." | ||
| 843 | (let ((dep-list | ||
| 844 | (delete-dups | ||
| 845 | (apply #'append | ||
| 846 | (mapcar (lambda (p) (mapcar #'car (package-desc-reqs (cadr p)))) | ||
| 847 | package-alist))))) | ||
| 848 | (cl-loop for p in package-alist | ||
| 849 | for name = (car p) | ||
| 850 | unless (memq name dep-list) | ||
| 851 | collect name))) | ||
| 852 | |||
| 853 | (defun package--save-selected-packages (&optional value) | ||
| 854 | "Set and save `package-selected-packages' to VALUE." | ||
| 855 | (when (or value after-init-time) | ||
| 856 | ;; It is valid to set it to nil, for example when the last package | ||
| 857 | ;; is uninstalled. But it shouldn't be done at init time, to | ||
| 858 | ;; avoid overwriting configurations that haven't yet been loaded. | ||
| 859 | (setq package-selected-packages (sort value #'string<))) | ||
| 860 | (if after-init-time | ||
| 861 | (customize-save-variable 'package-selected-packages package-selected-packages) | ||
| 862 | (add-hook 'after-init-hook #'package--save-selected-packages))) | ||
| 863 | |||
| 864 | (defun package--user-selected-p (pkg) | ||
| 865 | "Return non-nil if PKG is a package was installed by the user. | ||
| 866 | PKG is a package name. | ||
| 867 | This looks into `package-selected-packages', populating it first | ||
| 868 | if it is still empty." | ||
| 869 | (unless (consp package-selected-packages) | ||
| 870 | (package--save-selected-packages (package--find-non-dependencies))) | ||
| 871 | (memq pkg package-selected-packages)) | ||
| 872 | |||
| 873 | (defun package-desc-status (pkg-desc) | ||
| 874 | "Return the status of `package-desc' object PKG-DESC." | ||
| 875 | (let* ((name (package-desc-name pkg-desc)) | ||
| 876 | (dir (package-desc-dir pkg-desc)) | ||
| 877 | (lle (assq name package-load-list)) | ||
| 878 | (held (cadr lle)) | ||
| 879 | (version (package-desc-version pkg-desc)) | ||
| 880 | (signed (or (not package-list-unsigned) | ||
| 881 | (package-desc-signed pkg-desc)))) | ||
| 882 | (cond | ||
| 883 | ((package-vc-p pkg-desc) "source") | ||
| 884 | ((eq dir 'builtin) "built-in") | ||
| 885 | ((and lle (null held)) "disabled") | ||
| 886 | ((stringp held) | ||
| 887 | (let ((hv (if (stringp held) (version-to-list held)))) | ||
| 888 | (cond | ||
| 889 | ((version-list-= version hv) "held") | ||
| 890 | ((version-list-< version hv) "obsolete") | ||
| 891 | (t "disabled")))) | ||
| 892 | (dir ;One of the installed packages. | ||
| 893 | (cond | ||
| 894 | ((not (file-exists-p dir)) "deleted") | ||
| 895 | ;; Not inside `package-user-dir'. | ||
| 896 | ((not (file-in-directory-p dir package-user-dir)) "external") | ||
| 897 | ((eq pkg-desc (cadr (assq name package-alist))) | ||
| 898 | (if (not signed) "unsigned" | ||
| 899 | (if (package--user-selected-p name) | ||
| 900 | "installed" "dependency"))) | ||
| 901 | (t "obsolete"))) | ||
| 902 | ((package--incompatible-p pkg-desc) "incompat") | ||
| 903 | (t | ||
| 904 | (let* ((ins (cadr (assq name package-alist))) | ||
| 905 | (ins-v (if ins (package-desc-version ins)))) | ||
| 906 | (cond | ||
| 907 | ;; Installed obsolete packages are handled in the `dir' | ||
| 908 | ;; clause above. Here we handle available obsolete, which | ||
| 909 | ;; are displayed depending on `package-menu--hide-packages'. | ||
| 910 | ((and ins (version-list-<= version ins-v)) "avail-obso") | ||
| 911 | (t | ||
| 912 | (if (memq name (bound-and-true-p package-menu--new-package-list)) | ||
| 913 | "new" "available")))))))) | ||
| 914 | |||
| 915 | (defun package--query-desc (&optional alist) | ||
| 916 | "Query the user for a package or return the package at point. | ||
| 917 | The optional argument ALIST must consist of elements with the | ||
| 918 | form (PKG-NAME PKG-DESC). If not specified, it will default to | ||
| 919 | `package-alist'." | ||
| 920 | (or (and (fboundp 'tabulated-list-get-id) | ||
| 921 | (tabulated-list-get-id)) | ||
| 922 | (let ((alist (or alist package-alist))) | ||
| 923 | (cadr (assoc (completing-read "Package: " alist nil t) | ||
| 924 | alist #'string=))))) | ||
| 925 | |||
| 926 | (provide 'package-core) | ||
| 927 | ;;; package-core.el ends here | ||