diff options
| author | Philip Kaludercic | 2026-01-06 18:10:11 +0100 |
|---|---|---|
| committer | Philip Kaludercic | 2026-01-06 18:10:11 +0100 |
| commit | 1ef21e2470fb2583aee16f53656ab6195e76ed6d (patch) | |
| tree | 985252ec079f9fd761e187145ec1fa6a5c1d04da | |
| parent | 4abbd7b9bdb492a935ba79c9f51e7f05388e3fbe (diff) | |
| parent | cf95894aded1edbc16ea6b608535866885339f93 (diff) | |
| download | emacs-feature/package-activate.tar.gz emacs-feature/package-activate.zip | |
Merge branch 'package-activate'feature/package-activate
| -rw-r--r-- | lisp/emacs-lisp/package-activate.el | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/package-activate.el b/lisp/emacs-lisp/package-activate.el new file mode 100644 index 00000000000..e56a4ea4bc5 --- /dev/null +++ b/lisp/emacs-lisp/package-activate.el | |||
| @@ -0,0 +1,535 @@ | |||
| 1 | ;;; package-activate.el --- Core of the Emacs Package Manager -*- lexical-binding:t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2007-2026 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 | ;; This file contains the core definitions of package.el used to | ||
| 30 | ;; activate packages at startup, as well as other functions that are | ||
| 31 | ;; useful without having to load the entirety of package.el. | ||
| 32 | |||
| 33 | ;;; Code: | ||
| 34 | |||
| 35 | (eval-when-compile (require 'cl-lib)) | ||
| 36 | |||
| 37 | (defcustom package-load-list '(all) | ||
| 38 | "List of packages for `package-activate-all' to make available. | ||
| 39 | Each element in this list should be a list (NAME VERSION), or the | ||
| 40 | symbol `all'. The symbol `all' says to make available the latest | ||
| 41 | installed versions of all packages not specified by other | ||
| 42 | elements. | ||
| 43 | |||
| 44 | For an element (NAME VERSION), NAME is a package name (a symbol). | ||
| 45 | VERSION should be t, a string, or nil. | ||
| 46 | If VERSION is t, the most recent version is made available. | ||
| 47 | If VERSION is a string, only that version is ever made available. | ||
| 48 | Any other version, even if newer, is silently ignored. | ||
| 49 | Hence, the package is \"held\" at that version. | ||
| 50 | If VERSION is nil, the package is not made available (it is \"disabled\")." | ||
| 51 | :type '(repeat (choice (const all) | ||
| 52 | (list :tag "Specific package" | ||
| 53 | (symbol :tag "Package name") | ||
| 54 | (choice :tag "Version" | ||
| 55 | (const :tag "disable" nil) | ||
| 56 | (const :tag "most recent" t) | ||
| 57 | (string :tag "specific version"))))) | ||
| 58 | :risky t | ||
| 59 | :version "24.1" | ||
| 60 | :group 'package) | ||
| 61 | |||
| 62 | (defvar package--default-summary "No description available.") | ||
| 63 | |||
| 64 | (define-inline package-vc-p (pkg-desc) | ||
| 65 | "Return non-nil if PKG-DESC is a VC package." | ||
| 66 | (inline-letevals (pkg-desc) | ||
| 67 | (inline-quote (eq (package-desc-kind ,pkg-desc) 'vc)))) | ||
| 68 | |||
| 69 | (cl-defstruct (package-desc | ||
| 70 | ;; Rename the default constructor from `make-package-desc'. | ||
| 71 | (:constructor package-desc-create) | ||
| 72 | ;; Has the same interface as the old `define-package', | ||
| 73 | ;; which is still used in the "foo-pkg.el" files. Extra | ||
| 74 | ;; options can be supported by adding additional keys. | ||
| 75 | (:constructor | ||
| 76 | package-desc-from-define | ||
| 77 | (name-string version-string &optional summary requirements | ||
| 78 | &rest rest-plist | ||
| 79 | &aux | ||
| 80 | (name (intern name-string)) | ||
| 81 | (version (if (eq (car-safe version-string) 'vc) | ||
| 82 | (version-to-list (cdr version-string)) | ||
| 83 | (version-to-list version-string))) | ||
| 84 | (reqs (mapcar (lambda (elt) | ||
| 85 | (list (car elt) | ||
| 86 | (version-to-list (cadr elt)))) | ||
| 87 | (if (eq 'quote (car requirements)) | ||
| 88 | (nth 1 requirements) | ||
| 89 | requirements))) | ||
| 90 | (kind (plist-get rest-plist :kind)) | ||
| 91 | (archive (plist-get rest-plist :archive)) | ||
| 92 | (extras (let (alist) | ||
| 93 | (while rest-plist | ||
| 94 | (unless (memq (car rest-plist) '(:kind :archive)) | ||
| 95 | (let ((value (cadr rest-plist))) | ||
| 96 | (when value | ||
| 97 | (push (cons (car rest-plist) | ||
| 98 | (if (eq (car-safe value) 'quote) | ||
| 99 | (cadr value) | ||
| 100 | value)) | ||
| 101 | alist)))) | ||
| 102 | (setq rest-plist (cddr rest-plist))) | ||
| 103 | alist))))) | ||
| 104 | "Structure containing information about an individual package. | ||
| 105 | Slots: | ||
| 106 | |||
| 107 | `name' Name of the package, as a symbol. | ||
| 108 | |||
| 109 | `version' Version of the package, as a version list. | ||
| 110 | |||
| 111 | `summary' Short description of the package, typically taken from | ||
| 112 | the first line of the file. | ||
| 113 | |||
| 114 | `reqs' Requirements of the package. A list of (PACKAGE | ||
| 115 | VERSION-LIST) naming the dependent package and the minimum | ||
| 116 | required version. | ||
| 117 | |||
| 118 | `kind' The distribution format of the package. Currently, it is | ||
| 119 | either `single', `tar', or (temporarily only) `dir'. In | ||
| 120 | addition, there is distribution format `vc', which is handled | ||
| 121 | by package-vc.el. | ||
| 122 | |||
| 123 | `archive' The name of the archive (as a string) whence this | ||
| 124 | package came. | ||
| 125 | |||
| 126 | `dir' The directory where the package is installed (if installed), | ||
| 127 | `builtin' if it is built-in, or nil otherwise. | ||
| 128 | |||
| 129 | `extras' Optional alist of additional keyword-value pairs. | ||
| 130 | |||
| 131 | `signed' Flag to indicate that the package is signed by provider." | ||
| 132 | name | ||
| 133 | version | ||
| 134 | (summary package--default-summary) | ||
| 135 | reqs | ||
| 136 | kind | ||
| 137 | archive | ||
| 138 | dir | ||
| 139 | extras | ||
| 140 | signed) | ||
| 141 | |||
| 142 | ;; Pseudo fields. | ||
| 143 | (defun package-version-join (vlist) | ||
| 144 | "Return the version string corresponding to the list VLIST. | ||
| 145 | This is, approximately, the inverse of `version-to-list'. | ||
| 146 | \(Actually, it returns only one of the possible inverses, since | ||
| 147 | `version-to-list' is a many-to-one operation.)" | ||
| 148 | (if (null vlist) | ||
| 149 | "" | ||
| 150 | (let ((str-list (list "." (int-to-string (car vlist))))) | ||
| 151 | (dolist (num (cdr vlist)) | ||
| 152 | (cond | ||
| 153 | ((>= num 0) | ||
| 154 | (push (int-to-string num) str-list) | ||
| 155 | (push "." str-list)) | ||
| 156 | ((< num -4) | ||
| 157 | (error "Invalid version list `%s'" vlist)) | ||
| 158 | (t | ||
| 159 | ;; pre, or beta, or alpha | ||
| 160 | (cond ((equal "." (car str-list)) | ||
| 161 | (pop str-list)) | ||
| 162 | ((not (string-match "[0-9]+" (car str-list))) | ||
| 163 | (error "Invalid version list `%s'" vlist))) | ||
| 164 | (push (cond ((= num -1) "pre") | ||
| 165 | ((= num -2) "beta") | ||
| 166 | ((= num -3) "alpha") | ||
| 167 | ((= num -4) "snapshot")) | ||
| 168 | str-list)))) | ||
| 169 | (if (equal "." (car str-list)) | ||
| 170 | (pop str-list)) | ||
| 171 | (apply #'concat (nreverse str-list))))) | ||
| 172 | |||
| 173 | (defun package-desc-full-name (pkg-desc) | ||
| 174 | "Return full name of package-desc object PKG-DESC. | ||
| 175 | This is the name of the package with its version appended." | ||
| 176 | (if (package-vc-p pkg-desc) | ||
| 177 | (symbol-name (package-desc-name pkg-desc)) | ||
| 178 | (format "%s-%s" | ||
| 179 | (package-desc-name pkg-desc) | ||
| 180 | (package-version-join (package-desc-version pkg-desc))))) | ||
| 181 | |||
| 182 | |||
| 183 | ;;; Installed packages | ||
| 184 | ;; The following variables store information about packages present in | ||
| 185 | ;; the system. The most important of these is `package-alist'. The | ||
| 186 | ;; command `package-activate-all' is also closely related to this | ||
| 187 | ;; section. | ||
| 188 | |||
| 189 | (defvar package--builtins nil | ||
| 190 | "Alist of built-in packages. | ||
| 191 | The actual value is initialized by loading the library | ||
| 192 | `finder-inf'; this is not done until it is needed, e.g. by the | ||
| 193 | function `package-built-in-p'. | ||
| 194 | |||
| 195 | Each element has the form (PKG . PACKAGE-BI-DESC), where PKG is a package | ||
| 196 | name (a symbol) and DESC is a `package--bi-desc' structure.") | ||
| 197 | (put 'package--builtins 'risky-local-variable t) | ||
| 198 | |||
| 199 | (defvar package-alist nil | ||
| 200 | "Alist of all packages available for activation. | ||
| 201 | Each element has the form (PKG . DESCS), where PKG is a package | ||
| 202 | name (a symbol) and DESCS is a non-empty list of `package-desc' | ||
| 203 | structures, sorted by decreasing versions. | ||
| 204 | |||
| 205 | This variable is set automatically by `package-load-descriptor', | ||
| 206 | called via `package-activate-all'. To change which packages are | ||
| 207 | loaded and/or activated, customize `package-load-list'.") | ||
| 208 | (put 'package-alist 'risky-local-variable t) | ||
| 209 | |||
| 210 | ;;;; Public interfaces for accessing built-in package info | ||
| 211 | |||
| 212 | ;;;###autoload | ||
| 213 | (defvar package-activated-list nil | ||
| 214 | ;; FIXME: This should implicitly include all builtin packages. | ||
| 215 | "List of the names of currently activated packages.") | ||
| 216 | (put 'package-activated-list 'risky-local-variable t) | ||
| 217 | |||
| 218 | ;;;; Populating `package-alist'. | ||
| 219 | |||
| 220 | ;; The following functions are called on each installed package by | ||
| 221 | ;; `package-load-all-descriptors', which ultimately populates the | ||
| 222 | ;; `package-alist' variable. | ||
| 223 | |||
| 224 | (defun package-process-define-package (exp) | ||
| 225 | "Process define-package expression EXP and push it to `package-alist'. | ||
| 226 | EXP should be a form read from a foo-pkg.el file. | ||
| 227 | Convert EXP into a `package-desc' object using the | ||
| 228 | `package-desc-from-define' constructor before pushing it to | ||
| 229 | `package-alist'. | ||
| 230 | |||
| 231 | If there already exists a package by the same name in | ||
| 232 | `package-alist', insert this object there such that the packages | ||
| 233 | are sorted with the highest version first." | ||
| 234 | (when (eq (car-safe exp) 'define-package) | ||
| 235 | (let* ((new-pkg-desc (apply #'package-desc-from-define (cdr exp))) | ||
| 236 | (name (package-desc-name new-pkg-desc)) | ||
| 237 | (version (package-desc-version new-pkg-desc)) | ||
| 238 | (old-pkgs (assq name package-alist))) | ||
| 239 | (if (null old-pkgs) | ||
| 240 | ;; If there's no old package, just add this to `package-alist'. | ||
| 241 | (push (list name new-pkg-desc) package-alist) | ||
| 242 | ;; If there is, insert the new package at the right place in the list. | ||
| 243 | (while | ||
| 244 | (if (and (cdr old-pkgs) | ||
| 245 | (version-list-< version | ||
| 246 | (package-desc-version (cadr old-pkgs)))) | ||
| 247 | (setq old-pkgs (cdr old-pkgs)) | ||
| 248 | (push new-pkg-desc (cdr old-pkgs)) | ||
| 249 | nil))) | ||
| 250 | new-pkg-desc))) | ||
| 251 | |||
| 252 | (defun package-load-descriptor (pkg-dir) | ||
| 253 | "Load the package description file in directory PKG-DIR. | ||
| 254 | Create a new `package-desc' object, add it to `package-alist' and | ||
| 255 | return it." | ||
| 256 | (let ((pkg-file (expand-file-name (package--description-file pkg-dir) | ||
| 257 | pkg-dir)) | ||
| 258 | (signed-file (concat pkg-dir ".signed"))) | ||
| 259 | (when (file-exists-p pkg-file) | ||
| 260 | (with-temp-buffer | ||
| 261 | (insert-file-contents pkg-file) | ||
| 262 | (goto-char (point-min)) | ||
| 263 | (let ((pkg-desc (or (package-process-define-package | ||
| 264 | (read (current-buffer))) | ||
| 265 | (error "Can't find define-package in %s" pkg-file)))) | ||
| 266 | (setf (package-desc-dir pkg-desc) pkg-dir) | ||
| 267 | (if (file-exists-p signed-file) | ||
| 268 | (setf (package-desc-signed pkg-desc) t)) | ||
| 269 | pkg-desc))))) | ||
| 270 | |||
| 271 | (defun package-load-all-descriptors () | ||
| 272 | "Load descriptors for installed Emacs Lisp packages. | ||
| 273 | This looks for package subdirectories in `package-user-dir' and | ||
| 274 | `package-directory-list'. The variable `package-load-list' | ||
| 275 | controls which package subdirectories may be loaded. | ||
| 276 | |||
| 277 | In each valid package subdirectory, this function loads the | ||
| 278 | description file containing a call to `define-package', which | ||
| 279 | updates `package-alist'." | ||
| 280 | (dolist (dir (cons package-user-dir package-directory-list)) | ||
| 281 | (when (file-directory-p dir) | ||
| 282 | (dolist (pkg-dir (directory-files dir t "\\`[^.]")) | ||
| 283 | (when (file-directory-p pkg-dir) | ||
| 284 | (package-load-descriptor pkg-dir)))))) | ||
| 285 | |||
| 286 | (defun package--alist () | ||
| 287 | "Return `package-alist', after computing it if needed." | ||
| 288 | (or package-alist | ||
| 289 | (progn (package-load-all-descriptors) | ||
| 290 | package-alist))) | ||
| 291 | |||
| 292 | |||
| 293 | ;;; Package activation | ||
| 294 | ;; Section for functions used by `package-activate', which see. | ||
| 295 | |||
| 296 | (defun package-disabled-p (pkg-name version) | ||
| 297 | "Return whether PKG-NAME at VERSION can be activated. | ||
| 298 | The decision is made according to `package-load-list'. | ||
| 299 | Return nil if the package can be activated. | ||
| 300 | Return t if the package is completely disabled. | ||
| 301 | Return the max version (as a string) if the package is held at a lower version." | ||
| 302 | (let ((force (assq pkg-name package-load-list))) | ||
| 303 | (cond ((null force) (not (memq 'all package-load-list))) | ||
| 304 | ((null (setq force (cadr force))) t) ; disabled | ||
| 305 | ((eq force t) nil) | ||
| 306 | ((stringp force) ; held | ||
| 307 | (unless (version-list-= version (version-to-list force)) | ||
| 308 | force)) | ||
| 309 | (t (error "Invalid element in `package-load-list'"))))) | ||
| 310 | |||
| 311 | (defun package-built-in-p (package &optional min-version) | ||
| 312 | "Return non-nil if PACKAGE is built-in to Emacs. | ||
| 313 | Optional arg MIN-VERSION, if non-nil, should be a version list | ||
| 314 | specifying the minimum acceptable version." | ||
| 315 | (if (package-desc-p package) ;; was built-in and then was converted | ||
| 316 | (eq 'builtin (package-desc-dir package)) | ||
| 317 | (let ((bi (assq package package--builtin-versions))) | ||
| 318 | (cond | ||
| 319 | (bi (version-list-<= min-version (cdr bi))) | ||
| 320 | ((remove 0 min-version) nil) | ||
| 321 | (t | ||
| 322 | (require 'finder-inf nil t) ; For `package--builtins'. | ||
| 323 | (assq package package--builtins)))))) | ||
| 324 | |||
| 325 | (defun package--autoloads-file-name (pkg-desc) | ||
| 326 | "Return the absolute name of the autoloads file, sans extension. | ||
| 327 | PKG-DESC is a `package-desc' object." | ||
| 328 | (expand-file-name | ||
| 329 | (format "%s-autoloads" (package-desc-name pkg-desc)) | ||
| 330 | (package-desc-dir pkg-desc))) | ||
| 331 | |||
| 332 | (defvar Info-directory-list) | ||
| 333 | (declare-function info-initialize "info" ()) | ||
| 334 | |||
| 335 | (defvar package--quickstart-pkgs t | ||
| 336 | "If set to a list, we're computing the set of pkgs to activate.") | ||
| 337 | |||
| 338 | (defun package--add-info-node (pkg-dir) | ||
| 339 | "Add info node located in PKG-DIR." | ||
| 340 | (when (file-exists-p (expand-file-name "dir" pkg-dir)) | ||
| 341 | ;; FIXME: not the friendliest, but simple. | ||
| 342 | (require 'info) | ||
| 343 | (info-initialize) | ||
| 344 | (add-to-list 'Info-directory-list pkg-dir))) | ||
| 345 | |||
| 346 | (defun package-activate-1 (pkg-desc &optional reload deps) | ||
| 347 | "Activate package given by PKG-DESC, even if it was already active. | ||
| 348 | If DEPS is non-nil, also activate its dependencies (unless they | ||
| 349 | are already activated). | ||
| 350 | If RELOAD is non-nil, also `load' any files inside the package which | ||
| 351 | correspond to previously loaded files." | ||
| 352 | (let* ((name (package-desc-name pkg-desc)) | ||
| 353 | (pkg-dir (package-desc-dir pkg-desc))) | ||
| 354 | (unless pkg-dir | ||
| 355 | (error "Internal error: unable to find directory for `%s'" | ||
| 356 | (package-desc-full-name pkg-desc))) | ||
| 357 | (catch 'exit | ||
| 358 | ;; Activate its dependencies recursively. | ||
| 359 | ;; FIXME: This doesn't check whether the activated version is the | ||
| 360 | ;; required version. | ||
| 361 | (when deps | ||
| 362 | (dolist (req (package-desc-reqs pkg-desc)) | ||
| 363 | (unless (package-activate (car req)) | ||
| 364 | (message "Unable to activate package `%s'.\nRequired package `%s-%s' is unavailable" | ||
| 365 | name (car req) (package-version-join (cadr req))) | ||
| 366 | (throw 'exit nil)))) | ||
| 367 | (if (listp package--quickstart-pkgs) | ||
| 368 | ;; We're only collecting the set of packages to activate! | ||
| 369 | (push pkg-desc package--quickstart-pkgs) | ||
| 370 | (when (or reload (assq name package--builtin-versions)) | ||
| 371 | (require 'package) | ||
| 372 | (package--reload-previously-loaded | ||
| 373 | pkg-desc (unless reload | ||
| 374 | "Package %S is activated too late. | ||
| 375 | The following files have already been loaded: %S"))) | ||
| 376 | (with-demoted-errors "Error loading autoloads: %s" | ||
| 377 | (load (package--autoloads-file-name pkg-desc) nil t))) | ||
| 378 | (package--add-info-node pkg-dir) | ||
| 379 | (push name package-activated-list) | ||
| 380 | ;; Don't return nil. | ||
| 381 | t))) | ||
| 382 | |||
| 383 | ;;;; `package-activate' | ||
| 384 | |||
| 385 | (defun package--get-activatable-pkg (pkg-name) | ||
| 386 | ;; Is "activatable" a word? | ||
| 387 | (let ((pkg-descs (cdr (assq pkg-name package-alist)))) | ||
| 388 | ;; Check if PACKAGE is available in `package-alist'. | ||
| 389 | (while | ||
| 390 | (when pkg-descs | ||
| 391 | (let ((available-version (package-desc-version (car pkg-descs)))) | ||
| 392 | (or (package-disabled-p pkg-name available-version) | ||
| 393 | ;; Prefer a builtin package. | ||
| 394 | (package-built-in-p pkg-name available-version)))) | ||
| 395 | (setq pkg-descs (cdr pkg-descs))) | ||
| 396 | (car pkg-descs))) | ||
| 397 | |||
| 398 | ;; This function activates a newer version of a package if an older | ||
| 399 | ;; one was already activated. It also loads a features of this | ||
| 400 | ;; package which were already loaded. | ||
| 401 | (defun package-activate (package &optional force) | ||
| 402 | "Activate the package named PACKAGE. | ||
| 403 | If FORCE is true, (re-)activate it if it's already activated. | ||
| 404 | Newer versions are always activated, regardless of FORCE." | ||
| 405 | (let ((pkg-desc (package--get-activatable-pkg package))) | ||
| 406 | (cond | ||
| 407 | ;; If no such package is found, maybe it's built-in. | ||
| 408 | ((null pkg-desc) | ||
| 409 | (package-built-in-p package)) | ||
| 410 | ;; If the package is already activated, just return t. | ||
| 411 | ((and (memq package package-activated-list) (not force)) | ||
| 412 | t) | ||
| 413 | ;; Otherwise, proceed with activation. | ||
| 414 | (t (package-activate-1 pkg-desc nil 'deps))))) | ||
| 415 | |||
| 416 | |||
| 417 | ;;; Installation -- Local operations | ||
| 418 | ;; This section contains a variety of features regarding installing a | ||
| 419 | ;; package to/from disk. This includes autoload generation, | ||
| 420 | ;; unpacking, compiling, as well as defining a package from the | ||
| 421 | ;; current buffer. | ||
| 422 | |||
| 423 | ;;;; Unpacking | ||
| 424 | |||
| 425 | ;;;###autoload | ||
| 426 | (defvar package--activated nil | ||
| 427 | "Non-nil if `package-activate-all' has been run.") | ||
| 428 | |||
| 429 | ;;;###autoload | ||
| 430 | (progn ;; Make the function usable without loading `package.el'. | ||
| 431 | (defun package-activate-all () | ||
| 432 | "Activate all installed packages. | ||
| 433 | The variable `package-load-list' controls which packages to load." | ||
| 434 | (setq package--activated t) | ||
| 435 | (let* ((elc (concat package-quickstart-file "c")) | ||
| 436 | (qs (if (file-readable-p elc) elc | ||
| 437 | (if (file-readable-p package-quickstart-file) | ||
| 438 | package-quickstart-file)))) | ||
| 439 | ;; The quickstart file presumes that it has a blank slate, | ||
| 440 | ;; so don't use it if we already activated some packages. | ||
| 441 | (or (and qs (not (bound-and-true-p package-activated-list)) | ||
| 442 | ;; Skip `load-source-file-function' which would slow us down by | ||
| 443 | ;; a factor 2 when loading the .el file (this assumes we were | ||
| 444 | ;; careful to save this file so it doesn't need any decoding). | ||
| 445 | (with-demoted-errors "Error during quickstart: %S" | ||
| 446 | (let ((load-source-file-function nil)) | ||
| 447 | (unless (boundp 'package-activated-list) | ||
| 448 | (setq package-activated-list nil)) | ||
| 449 | (load qs nil 'nomessage) | ||
| 450 | t))) | ||
| 451 | (progn | ||
| 452 | (require 'package) | ||
| 453 | ;; Silence the "unknown function" warning when this is compiled | ||
| 454 | ;; inside `loaddefs.el'. | ||
| 455 | ;; FIXME: We use `with-no-warnings' because the effect of | ||
| 456 | ;; `declare-function' is currently not scoped, so if we use | ||
| 457 | ;; it here, we end up with a redefinition warning instead :-) | ||
| 458 | (with-no-warnings | ||
| 459 | (package--activate-all))))))) | ||
| 460 | |||
| 461 | (defun package--activate-all () | ||
| 462 | (dolist (elt (package--alist)) | ||
| 463 | (condition-case err | ||
| 464 | (package-activate (car elt)) | ||
| 465 | ;; Don't let failure of activation of a package arbitrarily stop | ||
| 466 | ;; activation of further packages. | ||
| 467 | (error (message "%s" (error-message-string err)))))) | ||
| 468 | |||
| 469 | ;;;; Inferring package from current buffer | ||
| 470 | |||
| 471 | (declare-function lm-package-version "lisp-mnt" (&optional file)) | ||
| 472 | |||
| 473 | ;;;###autoload | ||
| 474 | (defun package-installed-p (package &optional min-version) | ||
| 475 | "Return non-nil if PACKAGE, of MIN-VERSION or newer, is installed. | ||
| 476 | If PACKAGE is a symbol, it is the package name and MIN-VERSION | ||
| 477 | should be a version list. | ||
| 478 | |||
| 479 | If PACKAGE is a `package-desc' object, MIN-VERSION is ignored." | ||
| 480 | (cond | ||
| 481 | ((package-desc-p package) | ||
| 482 | (let ((dir (package-desc-dir package))) | ||
| 483 | (and (stringp dir) | ||
| 484 | (file-exists-p dir)))) | ||
| 485 | ((and (not (bound-and-true-p package--initialized)) | ||
| 486 | (null min-version) | ||
| 487 | package-activated-list) | ||
| 488 | ;; We used the quickstart: make it possible to use package-installed-p | ||
| 489 | ;; even before package is fully initialized. | ||
| 490 | (or | ||
| 491 | (memq package package-activated-list) | ||
| 492 | ;; Also check built-in packages. | ||
| 493 | (package-built-in-p package min-version))) | ||
| 494 | (t | ||
| 495 | (or | ||
| 496 | (let ((pkg-descs (cdr (assq package (package--alist))))) | ||
| 497 | (and pkg-descs | ||
| 498 | (version-list-<= min-version | ||
| 499 | (package-desc-version (car pkg-descs))))) | ||
| 500 | ;; Also check built-in packages. | ||
| 501 | (package-built-in-p package min-version))))) | ||
| 502 | |||
| 503 | ;;;###autoload | ||
| 504 | (defun package-get-version () | ||
| 505 | "Return the version number of the package in which this is used. | ||
| 506 | Assumes it is used from an Elisp file placed inside the top-level directory | ||
| 507 | of an installed ELPA package. | ||
| 508 | The return value is a string (or nil in case we can't find it). | ||
| 509 | It works in more cases if the call is in the file which contains | ||
| 510 | the `Version:' header." | ||
| 511 | ;; In a sense, this is a lie, but it does just what we want: precomputes | ||
| 512 | ;; the version at compile time and hardcodes it into the .elc file! | ||
| 513 | (declare (pure t)) | ||
| 514 | ;; Hack alert! | ||
| 515 | (let ((file (or (macroexp-file-name) buffer-file-name))) | ||
| 516 | (cond | ||
| 517 | ((null file) nil) | ||
| 518 | ;; Packages are normally installed into directories named "<pkg>-<vers>", | ||
| 519 | ;; so get the version number from there. | ||
| 520 | ((string-match "/[^/]+-\\([0-9]\\(?:[0-9.]\\|pre\\|beta\\|alpha\\|snapshot\\)+\\)/[^/]+\\'" file) | ||
| 521 | (match-string 1 file)) | ||
| 522 | ;; For packages run straight from the an elpa.git clone, there's no | ||
| 523 | ;; "-<vers>" in the directory name, so we have to fetch the version | ||
| 524 | ;; the hard way. | ||
| 525 | (t | ||
| 526 | (let* ((pkgdir (file-name-directory file)) | ||
| 527 | (pkgname (file-name-nondirectory (directory-file-name pkgdir))) | ||
| 528 | (mainfile (expand-file-name (concat pkgname ".el") pkgdir))) | ||
| 529 | (unless (file-readable-p mainfile) (setq mainfile file)) | ||
| 530 | (when (file-readable-p mainfile) | ||
| 531 | (require 'lisp-mnt) | ||
| 532 | (lm-package-version mainfile))))))) | ||
| 533 | |||
| 534 | (provide 'package-activate) | ||
| 535 | ;;; package-activate.el ends here | ||