Update copyright notices for 2013.
[bpt/emacs.git] / lisp / emacs-lisp / package.el
CommitLineData
44198b6e
CY
1;;; package.el --- Simple package system for Emacs
2
ab422c4d 3;; Copyright (C) 2007-2013 Free Software Foundation, Inc.
44198b6e
CY
4
5;; Author: Tom Tromey <tromey@redhat.com>
6;; Created: 10 Mar 2007
e24b21b4 7;; Version: 1.0
44198b6e
CY
8;; Keywords: tools
9
10;; This file is part of GNU Emacs.
11
267b82ff 12;; GNU Emacs is free software: you can redistribute it and/or modify
44198b6e 13;; it under the terms of the GNU General Public License as published by
267b82ff
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
44198b6e
CY
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
267b82ff 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
44198b6e
CY
24
25;;; Change Log:
26
27;; 2 Apr 2007 - now using ChangeLog file
28;; 15 Mar 2007 - updated documentation
29;; 14 Mar 2007 - Changed how obsolete packages are handled
30;; 13 Mar 2007 - Wrote package-install-from-buffer
31;; 12 Mar 2007 - Wrote package-menu mode
32
33;;; Commentary:
34
35;; The idea behind package.el is to be able to download packages and
36;; install them. Packages are versioned and have versioned
37;; dependencies. Furthermore, this supports built-in packages which
38;; may or may not be newer than user-specified packages. This makes
39;; it possible to upgrade Emacs and automatically disable packages
40;; which have moved from external to core. (Note though that we don't
41;; currently register any of these, so this feature does not actually
42;; work.)
43
44198b6e
CY
44;; A package is described by its name and version. The distribution
45;; format is either a tar file or a single .el file.
46
47;; A tar file should be named "NAME-VERSION.tar". The tar file must
48;; unpack into a directory named after the package and version:
49;; "NAME-VERSION". It must contain a file named "PACKAGE-pkg.el"
50;; which consists of a call to define-package. It may also contain a
51;; "dir" file and the info files it references.
52
bc44bef7 53;; A .el file is named "NAME-VERSION.el" in the remote archive, but is
44198b6e
CY
54;; installed as simply "NAME.el" in a directory named "NAME-VERSION".
55
bc44bef7
PH
56;; The downloader downloads all dependent packages. By default,
57;; packages come from the official GNU sources, but others may be
58;; added by customizing the `package-archives' alist. Packages get
59;; byte-compiled at install time.
44198b6e
CY
60
61;; At activation time we will set up the load-path and the info path,
62;; and we will load the package's autoloads. If a package's
63;; dependencies are not available, we will not activate that package.
64
65;; Conceptually a package has multiple state transitions:
66;;
67;; * Download. Fetching the package from ELPA.
68;; * Install. Untar the package, or write the .el file, into
69;; ~/.emacs.d/elpa/ directory.
70;; * Byte compile. Currently this phase is done during install,
71;; but we may change this.
72;; * Activate. Evaluate the autoloads for the package to make it
73;; available to the user.
74;; * Load. Actually load the package and run some code from it.
75
76;; Other external functions you may want to use:
77;;
015eea59 78;; M-x list-packages
44198b6e
CY
79;; Enters a mode similar to buffer-menu which lets you manage
80;; packages. You can choose packages for install (mark with "i",
81;; then "x" to execute) or deletion (not implemented yet), and you
82;; can see what packages are available. This will automatically
83;; fetch the latest list of packages from ELPA.
84;;
44198b6e
CY
85;; M-x package-install-from-buffer
86;; Install a package consisting of a single .el file that appears
87;; in the current buffer. This only works for packages which
88;; define a Version header properly; package.el also supports the
89;; extension headers Package-Version (in case Version is an RCS id
90;; or similar), and Package-Requires (if the package requires other
91;; packages).
92;;
93;; M-x package-install-file
94;; Install a package from the indicated file. The package can be
95;; either a tar file or a .el file. A tar file must contain an
96;; appropriately-named "-pkg.el" file; a .el file must be properly
97;; formatted as with package-install-from-buffer.
98
99;;; Thanks:
100;;; (sorted by sort-lines):
101
102;; Jim Blandy <jimb@red-bean.com>
103;; Karl Fogel <kfogel@red-bean.com>
104;; Kevin Ryde <user42@zip.com.au>
105;; Lawrence Mitchell
106;; Michael Olson <mwolson@member.fsf.org>
107;; Sebastian Tennant <sebyte@smolny.plus.com>
108;; Stefan Monnier <monnier@iro.umontreal.ca>
109;; Vinicius Jose Latorre <viniciusjl@ig.com.br>
110;; Phil Hagelberg <phil@hagelb.org>
111
112;;; ToDo:
113
5580f89d
GM
114;; - a trust mechanism, since compiling a package can run arbitrary code.
115;; For example, download package signatures and check that they match.
44198b6e
CY
116;; - putting info dirs at the start of the info path means
117;; users see a weird ordering of categories. OTOH we want to
118;; override later entries. maybe emacs needs to enforce
119;; the standard layout?
120;; - put bytecode in a separate directory tree
121;; - perhaps give users a way to recompile their bytecode
122;; or do it automatically when emacs changes
123;; - give users a way to know whether a package is installed ok
124;; - give users a way to view a package's documentation when it
125;; only appears in the .el
126;; - use/extend checkdoc so people can tell if their package will work
127;; - "installed" instead of a blank in the status column
128;; - tramp needs its files to be compiled in a certain order.
129;; how to handle this? fix tramp?
130;; - on emacs 21 we don't kill the -autoloads.el buffer. what about 22?
131;; - maybe we need separate .elc directories for various emacs versions
132;; and also emacs-vs-xemacs. That way conditional compilation can
133;; work. But would this break anything?
134;; - should store the package's keywords in archive-contents, then
135;; let the users filter the package-menu by keyword. See
136;; finder-by-keyword. (We could also let people view the
137;; Commentary, but it isn't clear how useful this is.)
138;; - William Xu suggests being able to open a package file without
139;; installing it
140;; - Interface with desktop.el so that restarting after an install
141;; works properly
142;; - Implement M-x package-upgrade, to upgrade any/all existing packages
143;; - Use hierarchical layout. PKG/etc PKG/lisp PKG/info
144;; ... except maybe lisp?
145;; - It may be nice to have a macro that expands to the package's
146;; private data dir, aka ".../etc". Or, maybe data-directory
147;; needs to be a list (though this would be less nice)
148;; a few packages want this, eg sokoban
149;; - package menu needs:
150;; ability to know which packages are built-in & thus not deletable
151;; it can sometimes print odd results, like 0.3 available but 0.4 active
152;; why is that?
153;; - Allow multiple versions on the server...?
154;; [ why bother? ]
155;; - Don't install a package which will invalidate dependencies overall
156;; - Allow something like (or (>= emacs 21.0) (>= xemacs 21.5))
157;; [ currently thinking, why bother.. KISS ]
158;; - Allow optional package dependencies
159;; then if we require 'bbdb', bbdb-specific lisp in lisp/bbdb
160;; and just don't compile to add to load path ...?
161;; - Have a list of archive URLs? [ maybe there's no point ]
162;; - David Kastrup pointed out on the xemacs list that for GPL it
163;; is friendlier to ship the source tree. We could "support" that
164;; by just having a "src" subdir in the package. This isn't ideal
165;; but it probably is not worth trying to support random source
166;; tree layouts, build schemes, etc.
167;; - Our treatment of the info path is somewhat bogus
168;; - perhaps have an "unstable" tree in ELPA as well as a stable one
169
170;;; Code:
171
e91a96fe
CY
172(require 'tabulated-list)
173
44198b6e
CY
174(defgroup package nil
175 "Manager for Emacs Lisp packages."
176 :group 'applications
177 :version "24.1")
178
179;;;###autoload
180(defcustom package-enable-at-startup t
181 "Whether to activate installed packages when Emacs starts.
182If non-nil, packages are activated after reading the init file
183and before `after-init-hook'. Activation is not done if
184`user-init-file' is nil (e.g. Emacs was started with \"-q\").
185
186Even if the value is nil, you can type \\[package-initialize] to
187activate the package system at any time."
188 :type 'boolean
189 :group 'package
190 :version "24.1")
191
192(defcustom package-load-list '(all)
193 "List of packages for `package-initialize' to load.
194Each element in this list should be a list (NAME VERSION), or the
195symbol `all'. The symbol `all' says to load the latest installed
196versions of all packages not specified by other elements.
197
198For an element (NAME VERSION), NAME is a package name (a symbol).
199VERSION should be t, a string, or nil.
200If VERSION is t, all versions are loaded, though obsolete ones
201 will be put in `package-obsolete-alist' and not activated.
202If VERSION is a string, only that version is ever loaded.
203 Any other version, even if newer, is silently ignored.
204 Hence, the package is \"held\" at that version.
205If VERSION is nil, the package is not loaded (it is \"disabled\")."
206 :type '(repeat symbol)
bc44bef7 207 :risky t
44198b6e
CY
208 :group 'package
209 :version "24.1")
210
211(defvar Info-directory-list)
44198b6e
CY
212(declare-function info-initialize "info" ())
213(declare-function url-http-parse-response "url-http" ())
214(declare-function lm-header "lisp-mnt" (header))
215(declare-function lm-commentary "lisp-mnt" (&optional file))
cb6c4991 216(defvar url-http-end-of-headers)
44198b6e 217
bc44bef7
PH
218(defcustom package-archives '(("gnu" . "http://elpa.gnu.org/packages/"))
219 "An alist of archives from which to fetch.
220The default value points to the GNU Emacs package repository.
f561e49a
CY
221
222Each element has the form (ID . LOCATION).
223 ID is an archive name, as a string.
224 LOCATION specifies the base location for the archive.
225 If it starts with \"http:\", it is treated as a HTTP URL;
226 otherwise it should be an absolute directory name.
5580f89d
GM
227 (Other types of URL are currently not supported.)
228
229Only add locations that you trust, since fetching and installing
230a package can run arbitrary code."
bc44bef7 231 :type '(alist :key-type (string :tag "Archive name")
f561e49a 232 :value-type (string :tag "URL or directory name"))
bc44bef7
PH
233 :risky t
234 :group 'package
235 :version "24.1")
44198b6e
CY
236
237(defconst package-archive-version 1
238 "Version number of the package archive understood by this file.
239Lower version numbers than this will probably be understood as well.")
240
241(defconst package-el-version "1.0"
242 "Version of package.el.")
243
244;; We don't prime the cache since it tends to get out of date.
245(defvar package-archive-contents nil
246 "Cache of the contents of the Emacs Lisp Package Archive.
247This is an alist mapping package names (symbols) to package
248descriptor vectors. These are like the vectors for `package-alist'
bc44bef7
PH
249but have extra entries: one which is 'tar for tar packages and
250'single for single-file packages, and one which is the name of
251the archive from which it came.")
252(put 'package-archive-contents 'risky-local-variable t)
44198b6e
CY
253
254(defcustom package-user-dir (locate-user-emacs-file "elpa")
255 "Directory containing the user's Emacs Lisp packages.
256The directory name should be absolute.
257Apart from this directory, Emacs also looks for system-wide
258packages in `package-directory-list'."
259 :type 'directory
bc44bef7 260 :risky t
44198b6e
CY
261 :group 'package
262 :version "24.1")
263
264(defcustom package-directory-list
265 ;; Defaults are subdirs named "elpa" in the site-lisp dirs.
266 (let (result)
267 (dolist (f load-path)
0be01d2c
CY
268 (and (stringp f)
269 (equal (file-name-nondirectory f) "site-lisp")
270 (push (expand-file-name "elpa" f) result)))
44198b6e
CY
271 (nreverse result))
272 "List of additional directories containing Emacs Lisp packages.
273Each directory name should be absolute.
274
275These directories contain packages intended for system-wide; in
276contrast, `package-user-dir' contains packages for personal use."
277 :type '(repeat directory)
bc44bef7 278 :risky t
44198b6e
CY
279 :group 'package
280 :version "24.1")
281
96ae4c8f 282;; The value is precomputed in finder-inf.el, but don't load that
cd1181db 283;; until it's needed (i.e. when `package-initialize' is called).
96ae4c8f
CY
284(defvar package--builtins nil
285 "Alist of built-in packages.
015eea59
CY
286The actual value is initialized by loading the library
287`finder-inf'; this is not done until it is needed, e.g. by the
288function `package-built-in-p'.
289
96ae4c8f
CY
290Each element has the form (PKG . DESC), where PKG is a package
291name (a symbol) and DESC is a vector that describes the package.
7ede3b65
CY
292The vector DESC has the form [VERSION-LIST REQS DOCSTRING].
293 VERSION-LIST is a version list.
294 REQS is a list of packages required by the package, each
295 requirement having the form (NAME VL), where NAME is a string
296 and VL is a version list.
96ae4c8f 297 DOCSTRING is a brief description of the package.")
bc44bef7 298(put 'package--builtins 'risky-local-variable t)
44198b6e 299
96ae4c8f 300(defvar package-alist nil
44198b6e 301 "Alist of all packages available for activation.
96ae4c8f
CY
302Each element has the form (PKG . DESC), where PKG is a package
303name (a symbol) and DESC is a vector that describes the package.
44198b6e 304
7ede3b65
CY
305The vector DESC has the form [VERSION-LIST REQS DOCSTRING].
306 VERSION-LIST is a version list.
307 REQS is a list of packages required by the package, each
308 requirement having the form (NAME VL) where NAME is a string
309 and VL is a version list.
96ae4c8f
CY
310 DOCSTRING is a brief description of the package.
311
312This variable is set automatically by `package-load-descriptor',
313called via `package-initialize'. To change which packages are
314loaded and/or activated, customize `package-load-list'.")
25322144 315(put 'package-alist 'risky-local-variable t)
44198b6e 316
96ae4c8f 317(defvar package-activated-list nil
44198b6e 318 "List of the names of currently activated packages.")
bc44bef7 319(put 'package-activated-list 'risky-local-variable t)
44198b6e
CY
320
321(defvar package-obsolete-alist nil
322 "Representation of obsolete packages.
323Like `package-alist', but maps package name to a second alist.
324The inner alist is keyed by version.")
bc44bef7 325(put 'package-obsolete-alist 'risky-local-variable t)
44198b6e 326
ba08b241
CY
327(defun package-version-join (vlist)
328 "Return the version string corresponding to the list VLIST.
329This is, approximately, the inverse of `version-to-list'.
330\(Actually, it returns only one of the possible inverses, since
331`version-to-list' is a many-to-one operation.)"
332 (if (null vlist)
333 ""
334 (let ((str-list (list "." (int-to-string (car vlist)))))
335 (dolist (num (cdr vlist))
336 (cond
337 ((>= num 0)
338 (push (int-to-string num) str-list)
339 (push "." str-list))
340 ((< num -3)
341 (error "Invalid version list `%s'" vlist))
342 (t
343 ;; pre, or beta, or alpha
344 (cond ((equal "." (car str-list))
345 (pop str-list))
346 ((not (string-match "[0-9]+" (car str-list)))
347 (error "Invalid version list `%s'" vlist)))
348 (push (cond ((= num -1) "pre")
349 ((= num -2) "beta")
350 ((= num -3) "alpha"))
351 str-list))))
352 (if (equal "." (car str-list))
353 (pop str-list))
354 (apply 'concat (nreverse str-list)))))
44198b6e 355
44198b6e
CY
356(defun package-strip-version (dirname)
357 "Strip the version from a combined package name and version.
358E.g., if given \"quux-23.0\", will return \"quux\""
4525ce3e 359 (if (string-match (concat "\\`" package-subdirectory-regexp "\\'") dirname)
44198b6e
CY
360 (match-string 1 dirname)))
361
362(defun package-load-descriptor (dir package)
4b99edf2 363 "Load the description file in directory DIR for package PACKAGE.
7ede3b65
CY
364Here, PACKAGE is a string of the form NAME-VERSION, where NAME is
365the package name and VERSION is its version."
bc44bef7
PH
366 (let* ((pkg-dir (expand-file-name package dir))
367 (pkg-file (expand-file-name
368 (concat (package-strip-version package) "-pkg")
369 pkg-dir)))
370 (when (and (file-directory-p pkg-dir)
371 (file-exists-p (concat pkg-file ".el")))
372 (load pkg-file nil t))))
44198b6e
CY
373
374(defun package-load-all-descriptors ()
375 "Load descriptors for installed Emacs Lisp packages.
376This looks for package subdirectories in `package-user-dir' and
377`package-directory-list'. The variable `package-load-list'
378controls which package subdirectories may be loaded.
379
380In each valid package subdirectory, this function loads the
381description file containing a call to `define-package', which
382updates `package-alist' and `package-obsolete-alist'."
0ce8e868 383 (let ((regexp (concat "\\`" package-subdirectory-regexp "\\'")))
44198b6e
CY
384 (dolist (dir (cons package-user-dir package-directory-list))
385 (when (file-directory-p dir)
386 (dolist (subdir (directory-files dir))
0ce8e868
CY
387 (when (string-match regexp subdir)
388 (package-maybe-load-descriptor (match-string 1 subdir)
389 (match-string 2 subdir)
390 dir)))))))
391
392(defun package-maybe-load-descriptor (name version dir)
393 "Maybe load a specific package from directory DIR.
394NAME and VERSION are the package's name and version strings.
395This function checks `package-load-list', before actually loading
396the package by calling `package-load-descriptor'."
397 (let ((force (assq (intern name) package-load-list))
398 (subdir (concat name "-" version)))
399 (and (file-directory-p (expand-file-name subdir dir))
400 ;; Check `package-load-list':
401 (cond ((null force)
402 (memq 'all package-load-list))
403 ((null (setq force (cadr force)))
404 nil) ; disabled
405 ((eq force t)
406 t)
407 ((stringp force) ; held
408 (version-list-= (version-to-list version)
409 (version-to-list force)))
410 (t
411 (error "Invalid element in `package-load-list'")))
412 ;; Actually load the descriptor:
413 (package-load-descriptor dir subdir))))
44198b6e
CY
414
415(defsubst package-desc-vers (desc)
416 "Extract version from a package description vector."
417 (aref desc 0))
418
419(defsubst package-desc-reqs (desc)
420 "Extract requirements from a package description vector."
421 (aref desc 1))
422
423(defsubst package-desc-doc (desc)
424 "Extract doc string from a package description vector."
425 (aref desc 2))
426
427(defsubst package-desc-kind (desc)
428 "Extract the kind of download from an archive package description vector."
429 (aref desc 3))
430
015eea59
CY
431(defun package--dir (name version)
432 "Return the directory where a package is installed, or nil if none.
433NAME and VERSION are both strings."
434 (let* ((subdir (concat name "-" version))
44198b6e 435 (dir-list (cons package-user-dir package-directory-list))
cced7584 436 pkg-dir)
44198b6e 437 (while dir-list
cced7584
CY
438 (let ((subdir-full (expand-file-name subdir (car dir-list))))
439 (if (file-directory-p subdir-full)
440 (setq pkg-dir subdir-full
441 dir-list nil)
44198b6e 442 (setq dir-list (cdr dir-list)))))
cced7584
CY
443 pkg-dir))
444
445(defun package-activate-1 (package pkg-vec)
446 (let* ((name (symbol-name package))
447 (version-str (package-version-join (package-desc-vers pkg-vec)))
448 (pkg-dir (package--dir name version-str)))
44198b6e 449 (unless pkg-dir
015eea59 450 (error "Internal error: unable to find directory for `%s-%s'"
cced7584
CY
451 name version-str))
452 ;; Add info node.
ebf662f4
CY
453 (when (file-exists-p (expand-file-name "dir" pkg-dir))
454 ;; FIXME: not the friendliest, but simple.
455 (require 'info)
456 (info-initialize)
457 (push pkg-dir Info-directory-list))
cced7584 458 ;; Add to load path, add autoloads, and activate the package.
ebf662f4 459 (push pkg-dir load-path)
cced7584 460 (load (expand-file-name (concat name "-autoloads") pkg-dir) nil t)
ebf662f4 461 (push package package-activated-list)
44198b6e
CY
462 ;; Don't return nil.
463 t))
464
7ede3b65
CY
465(defun package-built-in-p (package &optional min-version)
466 "Return true if PACKAGE is built-in to Emacs.
467Optional arg MIN-VERSION, if non-nil, should be a version list
468specifying the minimum acceptable version."
4b99edf2 469 (require 'finder-inf nil t) ; For `package--builtins'.
25f292cd
CY
470 (if (eq package 'emacs)
471 (version-list-<= min-version (version-to-list emacs-version))
472 (let ((elt (assq package package--builtins)))
473 (and elt (version-list-<= min-version
474 (package-desc-vers (cdr elt)))))))
44198b6e 475
4b99edf2
CY
476;; This function goes ahead and activates a newer version of a package
477;; if an older one was already activated. This is not ideal; we'd at
478;; least need to check to see if the package has actually been loaded,
479;; and not merely activated.
7ede3b65
CY
480(defun package-activate (package min-version)
481 "Activate package PACKAGE, of version MIN-VERSION or newer.
482MIN-VERSION should be a version list.
4b99edf2 483If PACKAGE has any dependencies, recursively activate them.
44198b6e 484Return nil if the package could not be activated."
4b99edf2
CY
485 (let ((pkg-vec (cdr (assq package package-alist)))
486 available-version found)
487 ;; Check if PACKAGE is available in `package-alist'.
488 (when pkg-vec
489 (setq available-version (package-desc-vers pkg-vec)
7ede3b65 490 found (version-list-<= min-version available-version)))
4b99edf2
CY
491 (cond
492 ;; If no such package is found, maybe it's built-in.
493 ((null found)
7ede3b65 494 (package-built-in-p package min-version))
4b99edf2
CY
495 ;; If the package is already activated, just return t.
496 ((memq package package-activated-list)
497 t)
498 ;; Otherwise, proceed with activation.
499 (t
500 (let ((fail (catch 'dep-failure
501 ;; Activate its dependencies recursively.
502 (dolist (req (package-desc-reqs pkg-vec))
503 (unless (package-activate (car req) (cadr req))
504 (throw 'dep-failure req))))))
505 (if fail
506 (warn "Unable to activate package `%s'.
015eea59 507Required package `%s-%s' is unavailable"
4b99edf2
CY
508 package (car fail) (package-version-join (cadr fail)))
509 ;; If all goes well, activate the package itself.
510 (package-activate-1 package pkg-vec)))))))
44198b6e
CY
511
512(defun package-mark-obsolete (package pkg-vec)
513 "Put package on the obsolete list, if not already there."
514 (let ((elt (assq package package-obsolete-alist)))
515 (if elt
516 ;; If this obsolete version does not exist in the list, update
517 ;; it the list.
518 (unless (assoc (package-desc-vers pkg-vec) (cdr elt))
519 (setcdr elt (cons (cons (package-desc-vers pkg-vec) pkg-vec)
520 (cdr elt))))
521 ;; Make a new association.
ebf662f4
CY
522 (push (cons package (list (cons (package-desc-vers pkg-vec)
523 pkg-vec)))
524 package-obsolete-alist))))
44198b6e 525
4b99edf2 526(defun define-package (name-string version-string
187d3296 527 &optional docstring requirements
4d6769e1 528 &rest _extra-properties)
44198b6e 529 "Define a new package.
4b99edf2 530NAME-STRING is the name of the package, as a string.
7ede3b65 531VERSION-STRING is the version of the package, as a string.
4b99edf2
CY
532DOCSTRING is a short description of the package, a string.
533REQUIREMENTS is a list of dependencies on other packages.
7ede3b65
CY
534 Each requirement is of the form (OTHER-PACKAGE OTHER-VERSION),
535 where OTHER-VERSION is a string.
187d3296
CY
536
537EXTRA-PROPERTIES is currently unused."
4b99edf2
CY
538 (let* ((name (intern name-string))
539 (version (version-to-list version-string))
44198b6e
CY
540 (new-pkg-desc
541 (cons name
4b99edf2 542 (vector version
44198b6e
CY
543 (mapcar
544 (lambda (elt)
545 (list (car elt)
148cef8e 546 (version-to-list (car (cdr elt)))))
44198b6e 547 requirements)
4b99edf2
CY
548 docstring)))
549 (old-pkg (assq name package-alist)))
550 (cond
551 ;; If there's no old package, just add this to `package-alist'.
552 ((null old-pkg)
553 (push new-pkg-desc package-alist))
554 ((version-list-< (package-desc-vers (cdr old-pkg)) version)
555 ;; Remove the old package and declare it obsolete.
556 (package-mark-obsolete name (cdr old-pkg))
557 (setq package-alist (cons new-pkg-desc
558 (delq old-pkg package-alist))))
559 ;; You can have two packages with the same version, e.g. one in
560 ;; the system package directory and one in your private
561 ;; directory. We just let the first one win.
562 ((not (version-list-= (package-desc-vers (cdr old-pkg)) version))
563 ;; The package is born obsolete.
564 (package-mark-obsolete name (cdr new-pkg-desc))))))
44198b6e
CY
565
566;; From Emacs 22.
567(defun package-autoload-ensure-default-file (file)
568 "Make sure that the autoload file FILE exists and if not create it."
569 (unless (file-exists-p file)
570 (write-region
571 (concat ";;; " (file-name-nondirectory file)
572 " --- automatically extracted autoloads\n"
573 ";;\n"
574 ";;; Code:\n\n"
575 "\f\n;; Local Variables:\n"
576 ";; version-control: never\n"
577 ";; no-byte-compile: t\n"
578 ";; no-update-autoloads: t\n"
579 ";; End:\n"
580 ";;; " (file-name-nondirectory file)
581 " ends here\n")
582 nil file))
583 file)
584
585(defun package-generate-autoloads (name pkg-dir)
9a70f03d 586 (require 'autoload) ;Load before we let-bind generated-autoload-file!
44198b6e 587 (let* ((auto-name (concat name "-autoloads.el"))
4d6769e1 588 ;;(ignore-name (concat name "-pkg.el"))
44198b6e
CY
589 (generated-autoload-file (expand-file-name auto-name pkg-dir))
590 (version-control 'never))
44198b6e
CY
591 (unless (fboundp 'autoload-ensure-default-file)
592 (package-autoload-ensure-default-file generated-autoload-file))
cd44022c
DH
593 (update-directory-autoloads pkg-dir)
594 (let ((buf (find-buffer-visiting generated-autoload-file)))
595 (when buf (kill-buffer buf)))))
44198b6e 596
4525ce3e
CY
597(defvar tar-parse-info)
598(declare-function tar-untar-buffer "tar-mode" ())
3c94d7a6
CY
599(declare-function tar-header-name "tar-mode" (tar-header))
600(declare-function tar-header-link-type "tar-mode" (tar-header))
4525ce3e
CY
601
602(defun package-untar-buffer (dir)
44198b6e 603 "Untar the current buffer.
4525ce3e
CY
604This uses `tar-untar-buffer' from Tar mode. All files should
605untar into a directory named DIR; otherwise, signal an error."
44198b6e 606 (require 'tar-mode)
4525ce3e
CY
607 (tar-mode)
608 ;; Make sure everything extracts into DIR.
3c94d7a6
CY
609 (let ((regexp (concat "\\`" (regexp-quote (expand-file-name dir)) "/"))
610 (case-fold-search (memq system-type '(windows-nt ms-dos cygwin))))
4525ce3e 611 (dolist (tar-data tar-parse-info)
3c94d7a6
CY
612 (let ((name (expand-file-name (tar-header-name tar-data))))
613 (or (string-match regexp name)
614 ;; Tarballs created by some utilities don't list
615 ;; directories with a trailing slash (Bug#13136).
616 (and (string-equal dir name)
617 (eq (tar-header-link-type tar-data) 5))
618 (error "Package does not untar cleanly into directory %s/" dir)))))
4525ce3e 619 (tar-untar-buffer))
44198b6e 620
292112ed
CY
621(defun package-unpack (package version)
622 (let* ((name (symbol-name package))
623 (dirname (concat name "-" version))
4525ce3e 624 (pkg-dir (expand-file-name dirname package-user-dir)))
44198b6e 625 (make-directory package-user-dir t)
015eea59 626 ;; FIXME: should we delete PKG-DIR if it exists?
44198b6e 627 (let* ((default-directory (file-name-as-directory package-user-dir)))
4525ce3e 628 (package-untar-buffer dirname)
292112ed
CY
629 (package--make-autoloads-and-compile name pkg-dir))))
630
631(defun package--make-autoloads-and-compile (name pkg-dir)
632 "Generate autoloads and do byte-compilation for package named NAME.
633PKG-DIR is the name of the package directory."
634 (package-generate-autoloads name pkg-dir)
635 (let ((load-path (cons pkg-dir load-path)))
636 ;; We must load the autoloads file before byte compiling, in
637 ;; case there are magic cookies to set up non-trivial paths.
638 (load (expand-file-name (concat name "-autoloads") pkg-dir) nil t)
639 (byte-recompile-directory pkg-dir 0 t)))
44198b6e 640
c6affbde 641(defun package--write-file-no-coding (file-name)
bc44bef7 642 (let ((buffer-file-coding-system 'no-conversion))
c6affbde 643 (write-region (point-min) (point-max) file-name)))
bc44bef7 644
44198b6e
CY
645(defun package-unpack-single (file-name version desc requires)
646 "Install the contents of the current buffer as a package."
647 ;; Special case "package".
648 (if (string= file-name "package")
bc44bef7 649 (package--write-file-no-coding
c6affbde 650 (expand-file-name (concat file-name ".el") package-user-dir))
ba08b241
CY
651 (let* ((pkg-dir (expand-file-name (concat file-name "-"
652 (package-version-join
653 (version-to-list version)))
44198b6e
CY
654 package-user-dir))
655 (el-file (expand-file-name (concat file-name ".el") pkg-dir))
656 (pkg-file (expand-file-name (concat file-name "-pkg.el") pkg-dir)))
657 (make-directory pkg-dir t)
c6affbde 658 (package--write-file-no-coding el-file)
44198b6e
CY
659 (let ((print-level nil)
660 (print-length nil))
661 (write-region
662 (concat
663 (prin1-to-string
664 (list 'define-package
665 file-name
666 version
667 desc
668 (list 'quote
669 ;; Turn version lists into string form.
670 (mapcar
671 (lambda (elt)
672 (list (car elt)
015eea59 673 (package-version-join (cadr elt))))
44198b6e
CY
674 requires))))
675 "\n")
676 nil
677 pkg-file
678 nil nil nil 'excl))
292112ed 679 (package--make-autoloads-and-compile file-name pkg-dir))))
44198b6e 680
f561e49a
CY
681(defmacro package--with-work-buffer (location file &rest body)
682 "Run BODY in a buffer containing the contents of FILE at LOCATION.
683LOCATION is the base location of a package archive, and should be
684one of the URLs (or file names) specified in `package-archives'.
685FILE is the name of a file relative to that base location.
686
687This macro retrieves FILE from LOCATION into a temporary buffer,
688and evaluates BODY while that buffer is current. This work
689buffer is killed afterwards. Return the last value in BODY."
da91b5f2 690 `(let* ((http (string-match "\\`https?:" ,location))
f561e49a
CY
691 (buffer
692 (if http
693 (url-retrieve-synchronously (concat ,location ,file))
694 (generate-new-buffer "*package work buffer*"))))
695 (prog1
696 (with-current-buffer buffer
697 (if http
698 (progn (package-handle-response)
699 (re-search-forward "^$" nil 'move)
700 (forward-char)
701 (delete-region (point-min) (point)))
702 (unless (file-name-absolute-p ,location)
703 (error "Archive location %s is not an absolute file name"
704 ,location))
705 (insert-file-contents (expand-file-name ,file ,location)))
706 ,@body)
707 (kill-buffer buffer))))
708
44198b6e 709(defun package-handle-response ()
f561e49a 710 "Handle the response from a `url-retrieve-synchronously' call.
44198b6e
CY
711Parse the HTTP response and throw if an error occurred.
712The url package seems to require extra processing for this.
713This should be called in a `save-excursion', in the download buffer.
714It will move point to somewhere in the headers."
715 ;; We assume HTTP here.
716 (require 'url-http)
717 (let ((response (url-http-parse-response)))
718 (when (or (< response 200) (>= response 300))
44198b6e
CY
719 (error "Error during download request:%s"
720 (buffer-substring-no-properties (point) (progn
721 (end-of-line)
722 (point)))))))
723
724(defun package-download-single (name version desc requires)
725 "Download and install a single-file package."
f561e49a
CY
726 (let ((location (package-archive-base name))
727 (file (concat (symbol-name name) "-" version ".el")))
728 (package--with-work-buffer location file
729 (package-unpack-single (symbol-name name) version desc requires))))
44198b6e
CY
730
731(defun package-download-tar (name version)
732 "Download and install a tar package."
f561e49a
CY
733 (let ((location (package-archive-base name))
734 (file (concat (symbol-name name) "-" version ".tar")))
735 (package--with-work-buffer location file
736 (package-unpack name version))))
44198b6e 737
bc44bef7 738(defun package-installed-p (package &optional min-version)
7ede3b65
CY
739 "Return true if PACKAGE, of MIN-VERSION or newer, is installed.
740MIN-VERSION should be a version list."
a7723be6 741 (unless package--initialized (error "package.el is not yet initialized!"))
44198b6e 742 (let ((pkg-desc (assq package package-alist)))
4b99edf2
CY
743 (if pkg-desc
744 (version-list-<= min-version
745 (package-desc-vers (cdr pkg-desc)))
746 ;; Also check built-in packages.
747 (package-built-in-p package min-version))))
44198b6e 748
96ae4c8f
CY
749(defun package-compute-transaction (package-list requirements)
750 "Return a list of packages to be installed, including PACKAGE-LIST.
751PACKAGE-LIST should be a list of package names (symbols).
752
753REQUIREMENTS should be a list of additional requirements; each
7ede3b65
CY
754element in this list should have the form (PACKAGE VERSION-LIST),
755where PACKAGE is a package name and VERSION-LIST is the required
756version of that package.
96ae4c8f
CY
757
758This function recursively computes the requirements of the
759packages in REQUIREMENTS, and returns a list of all the packages
760that must be installed. Packages that are already installed are
761not included in this list."
44198b6e
CY
762 (dolist (elt requirements)
763 (let* ((next-pkg (car elt))
764 (next-version (cadr elt)))
765 (unless (package-installed-p next-pkg next-version)
766 ;; A package is required, but not installed. It might also be
767 ;; blocked via `package-load-list'.
768 (let ((pkg-desc (assq next-pkg package-archive-contents))
769 hold)
770 (when (setq hold (assq next-pkg package-load-list))
771 (setq hold (cadr hold))
8ac9e529
DH
772 (cond ((eq hold t))
773 ((eq hold nil)
44198b6e
CY
774 (error "Required package '%s' is disabled"
775 (symbol-name next-pkg)))
776 ((null (stringp hold))
777 (error "Invalid element in `package-load-list'"))
148cef8e 778 ((version-list-< (version-to-list hold) next-version)
015eea59 779 (error "Package `%s' held at version %s, \
44198b6e
CY
780but version %s required"
781 (symbol-name next-pkg) hold
782 (package-version-join next-version)))))
783 (unless pkg-desc
015eea59 784 (error "Package `%s-%s' is unavailable"
4b99edf2
CY
785 (symbol-name next-pkg)
786 (package-version-join next-version)))
148cef8e
CY
787 (unless (version-list-<= next-version
788 (package-desc-vers (cdr pkg-desc)))
44198b6e 789 (error
015eea59 790 "Need package `%s-%s', but only %s is available"
44198b6e
CY
791 (symbol-name next-pkg) (package-version-join next-version)
792 (package-version-join (package-desc-vers (cdr pkg-desc)))))
793 ;; Only add to the transaction if we don't already have it.
96ae4c8f 794 (unless (memq next-pkg package-list)
ebf662f4 795 (push next-pkg package-list))
96ae4c8f
CY
796 (setq package-list
797 (package-compute-transaction package-list
44198b6e
CY
798 (package-desc-reqs
799 (cdr pkg-desc))))))))
96ae4c8f 800 package-list)
44198b6e
CY
801
802(defun package-read-from-string (str)
803 "Read a Lisp expression from STR.
804Signal an error if the entire string was not used."
805 (let* ((read-data (read-from-string str))
187d3296
CY
806 (more-left
807 (condition-case nil
808 ;; The call to `ignore' suppresses a compiler warning.
809 (progn (ignore (read-from-string
810 (substring str (cdr read-data))))
811 t)
812 (end-of-file nil))))
44198b6e
CY
813 (if more-left
814 (error "Can't read whole string")
815 (car read-data))))
816
817(defun package--read-archive-file (file)
818 "Re-read archive file FILE, if it exists.
819Will return the data from the file, or nil if the file does not exist.
820Will throw an error if the archive version is too new."
821 (let ((filename (expand-file-name file package-user-dir)))
187d3296
CY
822 (when (file-exists-p filename)
823 (with-temp-buffer
824 (insert-file-contents-literally filename)
825 (let ((contents (read (current-buffer))))
826 (if (> (car contents) package-archive-version)
827 (error "Package archive version %d is higher than %d"
828 (car contents) package-archive-version))
829 (cdr contents))))))
44198b6e 830
bc44bef7 831(defun package-read-all-archive-contents ()
96ae4c8f
CY
832 "Re-read `archive-contents', if it exists.
833If successful, set `package-archive-contents'."
fbe3be3f 834 (setq package-archive-contents nil)
bc44bef7 835 (dolist (archive package-archives)
96ae4c8f 836 (package-read-archive-contents (car archive))))
44198b6e 837
bc44bef7 838(defun package-read-archive-contents (archive)
187d3296
CY
839 "Re-read archive contents for ARCHIVE.
840If successful, set the variable `package-archive-contents'.
bc44bef7 841If the archive version is too new, signal an error."
187d3296
CY
842 ;; Version 1 of 'archive-contents' is identical to our internal
843 ;; representation.
844 (let* ((dir (concat "archives/" archive))
845 (contents-file (concat dir "/archive-contents"))
846 contents)
847 (when (setq contents (package--read-archive-file contents-file))
848 (dolist (package contents)
849 (package--add-to-archive-contents package archive)))))
bc44bef7
PH
850
851(defun package--add-to-archive-contents (package archive)
852 "Add the PACKAGE from the given ARCHIVE if necessary.
853Also, add the originating archive to the end of the package vector."
854 (let* ((name (car package))
25322144
CY
855 (version (package-desc-vers (cdr package)))
856 (entry (cons name
bc44bef7 857 (vconcat (cdr package) (vector archive))))
25322144
CY
858 (existing-package (assq name package-archive-contents)))
859 (cond ((not existing-package)
860 (add-to-list 'package-archive-contents entry))
861 ((version-list-< (package-desc-vers (cdr existing-package))
862 version)
863 ;; Replace the entry with this one.
864 (setq package-archive-contents
865 (cons entry
866 (delq existing-package
867 package-archive-contents)))))))
bc44bef7 868
96ae4c8f
CY
869(defun package-download-transaction (package-list)
870 "Download and install all the packages in PACKAGE-LIST.
871PACKAGE-LIST should be a list of package names (symbols).
872This function assumes that all package requirements in
873PACKAGE-LIST are satisfied, i.e. that PACKAGE-LIST is computed
874using `package-compute-transaction'."
875 (dolist (elt package-list)
44198b6e
CY
876 (let* ((desc (cdr (assq elt package-archive-contents)))
877 ;; As an exception, if package is "held" in
878 ;; `package-load-list', download the held version.
879 (hold (cadr (assq elt package-load-list)))
880 (v-string (or (and (stringp hold) hold)
881 (package-version-join (package-desc-vers desc))))
882 (kind (package-desc-kind desc)))
883 (cond
884 ((eq kind 'tar)
885 (package-download-tar elt v-string))
886 ((eq kind 'single)
887 (package-download-single elt v-string
888 (package-desc-doc desc)
889 (package-desc-reqs desc)))
890 (t
0ce8e868
CY
891 (error "Unknown package kind: %s" (symbol-name kind))))
892 ;; If package A depends on package B, then A may `require' B
893 ;; during byte compilation. So we need to activate B before
894 ;; unpacking A.
895 (package-maybe-load-descriptor (symbol-name elt) v-string
896 package-user-dir)
897 (package-activate elt (version-to-list v-string)))))
44198b6e 898
7254299e
CY
899(defvar package--initialized nil)
900
44198b6e
CY
901;;;###autoload
902(defun package-install (name)
903 "Install the package named NAME.
7254299e
CY
904NAME should be the name of one of the available packages in an
905archive in `package-archives'. Interactively, prompt for NAME."
44198b6e 906 (interactive
7254299e
CY
907 (progn
908 ;; Initialize the package system to get the list of package
909 ;; symbols for completion.
910 (unless package--initialized
911 (package-initialize t))
70550acf
PH
912 (unless package-archive-contents
913 (package-refresh-contents))
7254299e
CY
914 (list (intern (completing-read
915 "Install package: "
916 (mapcar (lambda (elt)
917 (cons (symbol-name (car elt))
918 nil))
919 package-archive-contents)
920 nil t)))))
44198b6e
CY
921 (let ((pkg-desc (assq name package-archive-contents)))
922 (unless pkg-desc
015eea59 923 (error "Package `%s' is not available for installation"
44198b6e 924 (symbol-name name)))
bc44bef7
PH
925 (package-download-transaction
926 (package-compute-transaction (list name)
0ce8e868 927 (package-desc-reqs (cdr pkg-desc))))))
44198b6e 928
ffbf300e
CY
929(defun package-strip-rcs-id (str)
930 "Strip RCS version ID from the version string STR.
44198b6e
CY
931If the result looks like a dotted numeric version, return it.
932Otherwise return nil."
ffbf300e
CY
933 (when str
934 (when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str)
935 (setq str (substring str (match-end 0))))
936 (condition-case nil
937 (if (version-to-list str)
938 str)
939 (error nil))))
44198b6e
CY
940
941(defun package-buffer-info ()
187d3296
CY
942 "Return a vector describing the package in the current buffer.
943The vector has the form
944
945 [FILENAME REQUIRES DESCRIPTION VERSION COMMENTARY]
946
947FILENAME is the file name, a string, sans the \".el\" extension.
7ede3b65
CY
948REQUIRES is a list of requirements, each requirement having the
949 form (NAME VER); NAME is a string and VER is a version list.
187d3296 950DESCRIPTION is the package description, a string.
44198b6e
CY
951VERSION is the version, a string.
952COMMENTARY is the commentary section, a string, or nil if none.
187d3296
CY
953
954If the buffer does not contain a conforming package, signal an
955error. If there is a package, narrow the buffer to the file's
956boundaries."
44198b6e 957 (goto-char (point-min))
f677562b 958 (unless (re-search-forward "^;;; \\([^ ]*\\)\\.el ---[ \t]*\\(.*?\\)[ \t]*\\(-\\*-.*-\\*-[ \t]*\\)?$" nil t)
187d3296
CY
959 (error "Packages lacks a file header"))
960 (let ((file-name (match-string-no-properties 1))
961 (desc (match-string-no-properties 2))
962 (start (line-beginning-position)))
963 (unless (search-forward (concat ";;; " file-name ".el ends here"))
964 (error "Package lacks a terminating comment"))
965 ;; Try to include a trailing newline.
966 (forward-line)
967 (narrow-to-region start (point))
968 (require 'lisp-mnt)
969 ;; Use some headers we've invented to drive the process.
970 (let* ((requires-str (lm-header "package-requires"))
971 (requires (if requires-str
972 (package-read-from-string requires-str)))
973 ;; Prefer Package-Version; if defined, the package author
974 ;; probably wants us to use it. Otherwise try Version.
975 (pkg-version
976 (or (package-strip-rcs-id (lm-header "package-version"))
977 (package-strip-rcs-id (lm-header "version"))))
978 (commentary (lm-commentary)))
979 (unless pkg-version
980 (error
981 "Package lacks a \"Version\" or \"Package-Version\" header"))
982 ;; Turn string version numbers into list form.
983 (setq requires
984 (mapcar
985 (lambda (elt)
986 (list (car elt)
987 (version-to-list (car (cdr elt)))))
988 requires))
989 (vector file-name requires desc pkg-version commentary))))
44198b6e
CY
990
991(defun package-tar-file-info (file)
992 "Find package information for a tar file.
993FILE is the name of the tar file to examine.
994The return result is a vector like `package-buffer-info'."
b511b994
MA
995 (let ((default-directory (file-name-directory file))
996 (file (file-name-nondirectory file)))
4525ce3e
CY
997 (unless (string-match (concat "\\`" package-subdirectory-regexp "\\.tar\\'")
998 file)
b511b994
MA
999 (error "Invalid package name `%s'" file))
1000 (let* ((pkg-name (match-string-no-properties 1 file))
1001 (pkg-version (match-string-no-properties 2 file))
1002 ;; Extract the package descriptor.
1003 (pkg-def-contents (shell-command-to-string
1004 ;; Requires GNU tar.
1005 (concat "tar -xOf " file " "
1006
1007 pkg-name "-" pkg-version "/"
1008 pkg-name "-pkg.el")))
1009 (pkg-def-parsed (package-read-from-string pkg-def-contents)))
1010 (unless (eq (car pkg-def-parsed) 'define-package)
1011 (error "No `define-package' sexp is present in `%s-pkg.el'" pkg-name))
1012 (let ((name-str (nth 1 pkg-def-parsed))
1013 (version-string (nth 2 pkg-def-parsed))
1014 (docstring (nth 3 pkg-def-parsed))
1015 (requires (nth 4 pkg-def-parsed))
1016 (readme (shell-command-to-string
1017 ;; Requires GNU tar.
1018 (concat "tar -xOf " file " "
1019 pkg-name "-" pkg-version "/README"))))
1020 (unless (equal pkg-version version-string)
1021 (error "Package has inconsistent versions"))
1022 (unless (equal pkg-name name-str)
1023 (error "Package has inconsistent names"))
1024 ;; Kind of a hack.
1025 (if (string-match ": Not found in archive" readme)
1026 (setq readme nil))
1027 ;; Turn string version numbers into list form.
1028 (if (eq (car requires) 'quote)
1029 (setq requires (car (cdr requires))))
1030 (setq requires
1031 (mapcar (lambda (elt)
1032 (list (car elt)
1033 (version-to-list (cadr elt))))
1034 requires))
1035 (vector pkg-name requires docstring version-string readme)))))
44198b6e 1036
187d3296
CY
1037;;;###autoload
1038(defun package-install-from-buffer (pkg-info type)
1039 "Install a package from the current buffer.
1040When called interactively, the current buffer is assumed to be a
1041single .el file that follows the packaging guidelines; see info
1042node `(elisp)Packaging'.
1043
1044When called from Lisp, PKG-INFO is a vector describing the
1045information, of the type returned by `package-buffer-info'; and
1046TYPE is the package type (either `single' or `tar')."
1047 (interactive (list (package-buffer-info) 'single))
44198b6e
CY
1048 (save-excursion
1049 (save-restriction
1050 (let* ((file-name (aref pkg-info 0))
187d3296 1051 (requires (aref pkg-info 1))
44198b6e
CY
1052 (desc (if (string= (aref pkg-info 2) "")
1053 "No description available."
1054 (aref pkg-info 2)))
1055 (pkg-version (aref pkg-info 3)))
1056 ;; Download and install the dependencies.
1057 (let ((transaction (package-compute-transaction nil requires)))
1058 (package-download-transaction transaction))
1059 ;; Install the package itself.
1060 (cond
1061 ((eq type 'single)
1062 (package-unpack-single file-name pkg-version desc requires))
1063 ((eq type 'tar)
1064 (package-unpack (intern file-name) pkg-version))
1065 (t
1066 (error "Unknown type: %s" (symbol-name type))))
1067 ;; Try to activate it.
1068 (package-initialize)))))
1069
44198b6e
CY
1070;;;###autoload
1071(defun package-install-file (file)
1072 "Install a package from a file.
1073The file can either be a tar file or an Emacs Lisp file."
1074 (interactive "fPackage file name: ")
1075 (with-temp-buffer
1076 (insert-file-contents-literally file)
1077 (cond
187d3296
CY
1078 ((string-match "\\.el$" file)
1079 (package-install-from-buffer (package-buffer-info) 'single))
44198b6e 1080 ((string-match "\\.tar$" file)
187d3296 1081 (package-install-from-buffer (package-tar-file-info file) 'tar))
44198b6e
CY
1082 (t (error "Unrecognized extension `%s'" (file-name-extension file))))))
1083
1084(defun package-delete (name version)
015eea59
CY
1085 (let ((dir (package--dir name version)))
1086 (if (string-equal (file-name-directory dir)
1087 (file-name-as-directory
1088 (expand-file-name package-user-dir)))
1089 (progn
1090 (delete-directory dir t t)
1091 (message "Package `%s-%s' deleted." name version))
1092 ;; Don't delete "system" packages
1093 (error "Package `%s-%s' is a system package, not deleting"
1094 name version))))
44198b6e 1095
f561e49a 1096(defun package-archive-base (name)
bc44bef7
PH
1097 "Return the archive containing the package NAME."
1098 (let ((desc (cdr (assq (intern-soft name) package-archive-contents))))
1099 (cdr (assoc (aref desc (- (length desc) 1)) package-archives))))
1100
1101(defun package--download-one-archive (archive file)
f561e49a
CY
1102 "Retrieve an archive file FILE from ARCHIVE, and cache it.
1103ARCHIVE should be a cons cell of the form (NAME . LOCATION),
1104similar to an entry in `package-alist'. Save the cached copy to
1105\"archives/NAME/archive-contents\" in `package-user-dir'."
1106 (let* ((dir (expand-file-name "archives" package-user-dir))
1107 (dir (expand-file-name (car archive) dir)))
1108 (package--with-work-buffer (cdr archive) file
ebf662f4
CY
1109 ;; Read the retrieved buffer to make sure it is valid (e.g. it
1110 ;; may fetch a URL redirect page).
1111 (when (listp (read buffer))
1112 (make-directory dir t)
1113 (setq buffer-file-name (expand-file-name file dir))
1114 (let ((version-control 'never))
f561e49a 1115 (save-buffer))))))
44198b6e 1116
38bb2ca8 1117;;;###autoload
44198b6e
CY
1118(defun package-refresh-contents ()
1119 "Download the ELPA archive description if needed.
ebf662f4
CY
1120This informs Emacs about the latest versions of all packages, and
1121makes them available for download."
44198b6e
CY
1122 (interactive)
1123 (unless (file-exists-p package-user-dir)
1124 (make-directory package-user-dir t))
bc44bef7 1125 (dolist (archive package-archives)
1be3ca5a 1126 (condition-case-unless-debug nil
cb6c4991 1127 (package--download-one-archive archive "archive-contents")
187d3296 1128 (error (message "Failed to download `%s' archive."
cb6c4991 1129 (car archive)))))
bc44bef7 1130 (package-read-all-archive-contents))
44198b6e
CY
1131
1132;;;###autoload
4b99edf2 1133(defun package-initialize (&optional no-activate)
44198b6e 1134 "Load Emacs Lisp packages, and activate them.
4b99edf2
CY
1135The variable `package-load-list' controls which packages to load.
1136If optional arg NO-ACTIVATE is non-nil, don't activate packages."
44198b6e 1137 (interactive)
015eea59
CY
1138 (setq package-alist nil
1139 package-obsolete-alist nil)
44198b6e 1140 (package-load-all-descriptors)
bc44bef7 1141 (package-read-all-archive-contents)
4b99edf2
CY
1142 (unless no-activate
1143 (dolist (elt package-alist)
1144 (package-activate (car elt) (package-desc-vers (cdr elt)))))
1145 (setq package--initialized t))
44198b6e
CY
1146
1147\f
cced7584 1148;;;; Package description buffer.
44198b6e 1149
cced7584
CY
1150;;;###autoload
1151(defun describe-package (package)
1152 "Display the full documentation of PACKAGE (a symbol)."
1153 (interactive
8a500a91
CY
1154 (let* ((guess (function-called-at-point))
1155 packages val)
4b99edf2
CY
1156 (require 'finder-inf nil t)
1157 ;; Load the package list if necessary (but don't activate them).
1158 (unless package--initialized
1159 (package-initialize t))
8a500a91 1160 (setq packages (append (mapcar 'car package-alist)
4b99edf2
CY
1161 (mapcar 'car package-archive-contents)
1162 (mapcar 'car package--builtins)))
cced7584
CY
1163 (unless (memq guess packages)
1164 (setq guess nil))
1165 (setq packages (mapcar 'symbol-name packages))
1166 (setq val
1167 (completing-read (if guess
1168 (format "Describe package (default %s): "
1169 guess)
1170 "Describe package: ")
1171 packages nil t nil nil guess))
cb6c4991 1172 (list (if (equal val "") guess (intern val)))))
4b99edf2
CY
1173 (if (or (null package) (not (symbolp package)))
1174 (message "No package specified")
cced7584
CY
1175 (help-setup-xref (list #'describe-package package)
1176 (called-interactively-p 'interactive))
1177 (with-help-window (help-buffer)
1178 (with-current-buffer standard-output
1179 (describe-package-1 package)))))
1180
1181(defun describe-package-1 (package)
96ae4c8f 1182 (require 'lisp-mnt)
cb6c4991
CY
1183 (let ((package-name (symbol-name package))
1184 (built-in (assq package package--builtins))
1185 desc pkg-dir reqs version installable)
cced7584
CY
1186 (prin1 package)
1187 (princ " is ")
4b99edf2
CY
1188 (cond
1189 ;; Loaded packages are in `package-alist'.
1190 ((setq desc (cdr (assq package package-alist)))
1191 (setq version (package-version-join (package-desc-vers desc)))
1192 (if (setq pkg-dir (package--dir package-name version))
1193 (insert "an installed package.\n\n")
1194 ;; This normally does not happen.
1195 (insert "a deleted package.\n\n")))
1196 ;; Available packages are in `package-archive-contents'.
1197 ((setq desc (cdr (assq package package-archive-contents)))
1198 (setq version (package-version-join (package-desc-vers desc))
8adb4c33 1199 installable t)
4b99edf2
CY
1200 (if built-in
1201 (insert "a built-in package.\n\n")
1202 (insert "an uninstalled package.\n\n")))
1203 (built-in
1204 (setq desc (cdr built-in)
1205 version (package-version-join (package-desc-vers desc)))
1206 (insert "a built-in package.\n\n"))
1207 (t
1208 (insert "an orphan package.\n\n")))
cb6c4991 1209
96ae4c8f 1210 (insert " " (propertize "Status" 'font-lock-face 'bold) ": ")
cb6c4991 1211 (cond (pkg-dir
96ae4c8f
CY
1212 (insert (propertize "Installed"
1213 'font-lock-face 'font-lock-comment-face))
cb6c4991
CY
1214 (insert " in `")
1215 ;; Todo: Add button for uninstalling.
1216 (help-insert-xref-button (file-name-as-directory pkg-dir)
1217 'help-package-def pkg-dir)
4b99edf2
CY
1218 (if built-in
1219 (insert "',\n shadowing a "
1220 (propertize "built-in package"
1221 'font-lock-face 'font-lock-builtin-face)
1222 ".")
1223 (insert "'.")))
cb6c4991 1224 (installable
4b99edf2
CY
1225 (if built-in
1226 (insert (propertize "Built-in." 'font-lock-face 'font-lock-builtin-face)
1227 " Alternate version available -- ")
1228 (insert "Available -- "))
1229 (let ((button-text (if (display-graphic-p) "Install" "[Install]"))
cb6c4991
CY
1230 (button-face (if (display-graphic-p)
1231 '(:box (:line-width 2 :color "dark grey")
1232 :background "light grey"
1233 :foreground "black")
1234 'link)))
4b99edf2 1235 (insert-text-button button-text 'face button-face 'follow-link t
cb6c4991
CY
1236 'package-symbol package
1237 'action 'package-install-button-action)))
1238 (built-in
4b99edf2 1239 (insert (propertize "Built-in." 'font-lock-face 'font-lock-builtin-face)))
cb6c4991
CY
1240 (t (insert "Deleted.")))
1241 (insert "\n")
4b99edf2 1242 (and version (> (length version) 0)
96ae4c8f
CY
1243 (insert " "
1244 (propertize "Version" 'font-lock-face 'bold) ": " version "\n"))
4b99edf2
CY
1245
1246 (setq reqs (if desc (package-desc-reqs desc)))
8adb4c33 1247 (when reqs
96ae4c8f 1248 (insert " " (propertize "Requires" 'font-lock-face 'bold) ": ")
8adb4c33
CY
1249 (let ((first t)
1250 name vers text)
1251 (dolist (req reqs)
1252 (setq name (car req)
1253 vers (cadr req)
1254 text (format "%s-%s" (symbol-name name)
1255 (package-version-join vers)))
1256 (cond (first (setq first nil))
1257 ((>= (+ 2 (current-column) (length text))
1258 (window-width))
1259 (insert ",\n "))
1260 (t (insert ", ")))
1261 (help-insert-xref-button text 'help-package name))
1262 (insert "\n")))
96ae4c8f 1263 (insert " " (propertize "Summary" 'font-lock-face 'bold)
4b99edf2 1264 ": " (if desc (package-desc-doc desc)) "\n\n")
cb6c4991 1265
4b99edf2 1266 (if built-in
96ae4c8f
CY
1267 ;; For built-in packages, insert the commentary.
1268 (let ((fn (locate-file (concat package-name ".el") load-path
1269 load-file-rep-suffixes))
1270 (opoint (point)))
1271 (insert (or (lm-commentary fn) ""))
1272 (save-excursion
1273 (goto-char opoint)
1274 (when (re-search-forward "^;;; Commentary:\n" nil t)
1275 (replace-match ""))
1276 (while (re-search-forward "^\\(;+ ?\\)" nil t)
1277 (replace-match ""))))
1278 (let ((readme (expand-file-name (concat package-name "-readme.txt")
f561e49a
CY
1279 package-user-dir))
1280 readme-string)
96ae4c8f
CY
1281 ;; For elpa packages, try downloading the commentary. If that
1282 ;; fails, try an existing readme file in `package-user-dir'.
f561e49a
CY
1283 (cond ((condition-case nil
1284 (package--with-work-buffer (package-archive-base package)
1285 (concat package-name "-readme.txt")
1286 (setq buffer-file-name
1287 (expand-file-name readme package-user-dir))
1288 (let ((version-control 'never))
1289 (save-buffer))
1290 (setq readme-string (buffer-string))
1291 t)
1292 (error nil))
1293 (insert readme-string))
96ae4c8f
CY
1294 ((file-readable-p readme)
1295 (insert-file-contents readme)
1296 (goto-char (point-max))))))))
cb6c4991
CY
1297
1298(defun package-install-button-action (button)
1299 (let ((package (button-get button 'package-symbol)))
1300 (when (y-or-n-p (format "Install package `%s'? " package))
1301 (package-install package)
1302 (revert-buffer nil t)
1303 (goto-char (point-min)))))
cced7584
CY
1304
1305\f
44198b6e
CY
1306;;;; Package menu mode.
1307
54ea2a0d 1308(defvar package-menu-mode-map
e91a96fe 1309 (let ((map (make-sparse-keymap))
64eba874 1310 (menu-map (make-sparse-keymap "Package")))
e91a96fe 1311 (set-keymap-parent map tabulated-list-mode-map)
8adb4c33 1312 (define-key map "\C-m" 'package-menu-describe-package)
54ea2a0d
JB
1313 (define-key map "u" 'package-menu-mark-unmark)
1314 (define-key map "\177" 'package-menu-backup-unmark)
1315 (define-key map "d" 'package-menu-mark-delete)
1316 (define-key map "i" 'package-menu-mark-install)
25322144 1317 (define-key map "U" 'package-menu-mark-upgrades)
54ea2a0d
JB
1318 (define-key map "r" 'package-menu-refresh)
1319 (define-key map "~" 'package-menu-mark-obsolete-for-deletion)
1320 (define-key map "x" 'package-menu-execute)
1321 (define-key map "h" 'package-menu-quick-help)
cb6c4991 1322 (define-key map "?" 'package-menu-describe-package)
64eba874
DN
1323 (define-key map [menu-bar package-menu] (cons "Package" menu-map))
1324 (define-key menu-map [mq]
1325 '(menu-item "Quit" quit-window
1326 :help "Quit package selection"))
1327 (define-key menu-map [s1] '("--"))
1328 (define-key menu-map [mn]
1329 '(menu-item "Next" next-line
1330 :help "Next Line"))
1331 (define-key menu-map [mp]
1332 '(menu-item "Previous" previous-line
1333 :help "Previous Line"))
1334 (define-key menu-map [s2] '("--"))
1335 (define-key menu-map [mu]
1336 '(menu-item "Unmark" package-menu-mark-unmark
1337 :help "Clear any marks on a package and move to the next line"))
1338 (define-key menu-map [munm]
7cc6e154 1339 '(menu-item "Unmark Backwards" package-menu-backup-unmark
64eba874
DN
1340 :help "Back up one line and clear any marks on that package"))
1341 (define-key menu-map [md]
7cc6e154 1342 '(menu-item "Mark for Deletion" package-menu-mark-delete
64eba874
DN
1343 :help "Mark a package for deletion and move to the next line"))
1344 (define-key menu-map [mi]
7cc6e154 1345 '(menu-item "Mark for Install" package-menu-mark-install
64eba874 1346 :help "Mark a package for installation and move to the next line"))
d770725a 1347 (define-key menu-map [mupgrades]
7cc6e154 1348 '(menu-item "Mark Upgradable Packages" package-menu-mark-upgrades
d770725a 1349 :help "Mark packages that have a newer version for upgrading"))
64eba874
DN
1350 (define-key menu-map [s3] '("--"))
1351 (define-key menu-map [mg]
7cc6e154 1352 '(menu-item "Update Package List" revert-buffer
64eba874
DN
1353 :help "Update the list of packages"))
1354 (define-key menu-map [mr]
7cc6e154 1355 '(menu-item "Refresh Package List" package-menu-refresh
64eba874
DN
1356 :help "Download the ELPA archive"))
1357 (define-key menu-map [s4] '("--"))
1358 (define-key menu-map [mt]
7cc6e154 1359 '(menu-item "Mark Obsolete Packages" package-menu-mark-obsolete-for-deletion
64eba874
DN
1360 :help "Mark all obsolete packages for deletion"))
1361 (define-key menu-map [mx]
7cc6e154 1362 '(menu-item "Execute Actions" package-menu-execute
64eba874
DN
1363 :help "Perform all the marked actions"))
1364 (define-key menu-map [s5] '("--"))
1365 (define-key menu-map [mh]
1366 '(menu-item "Help" package-menu-quick-help
1367 :help "Show short key binding help for package-menu-mode"))
1368 (define-key menu-map [mc]
1369 '(menu-item "View Commentary" package-menu-view-commentary
1370 :help "Display information about this package"))
54ea2a0d 1371 map)
44198b6e
CY
1372 "Local keymap for `package-menu-mode' buffers.")
1373
60057926
CY
1374(defvar package-menu--new-package-list nil
1375 "List of newly-available packages since `list-packages' was last called.")
1376
e91a96fe 1377(define-derived-mode package-menu-mode tabulated-list-mode "Package Menu"
44198b6e
CY
1378 "Major mode for browsing a list of packages.
1379Letters do not insert themselves; instead, they are commands.
1380\\<package-menu-mode-map>
1381\\{package-menu-mode-map}"
e91a96fe
CY
1382 (setq tabulated-list-format [("Package" 18 package-menu--name-predicate)
1383 ("Version" 12 nil)
1384 ("Status" 10 package-menu--status-predicate)
1385 ("Description" 0 nil)])
1386 (setq tabulated-list-padding 2)
1387 (setq tabulated-list-sort-key (cons "Status" nil))
1388 (tabulated-list-init-header))
1389
1390(defmacro package--push (package desc status listname)
1391 "Convenience macro for `package-menu--generate'.
1392If the alist stored in the symbol LISTNAME lacks an entry for a
1393package PACKAGE with descriptor DESC, add one. The alist is
7ede3b65
CY
1394keyed with cons cells (PACKAGE . VERSION-LIST), where PACKAGE is
1395a symbol and VERSION-LIST is a version list."
e91a96fe
CY
1396 `(let* ((version (package-desc-vers ,desc))
1397 (key (cons ,package version)))
1398 (unless (assoc key ,listname)
1399 (push (list key ,status (package-desc-doc ,desc)) ,listname))))
1400
512e3ae1 1401(defun package-menu--generate (remember-pos packages)
e91a96fe 1402 "Populate the Package Menu.
512e3ae1
CY
1403If REMEMBER-POS is non-nil, keep point on the same entry.
1404PACKAGES should be t, which means to display all known packages,
1405or a list of package names (symbols) to display."
e91a96fe 1406 ;; Construct list of ((PACKAGE . VERSION) STATUS DESCRIPTION).
4d6769e1 1407 (let (info-list name)
e91a96fe
CY
1408 ;; Installed packages:
1409 (dolist (elt package-alist)
1410 (setq name (car elt))
512e3ae1
CY
1411 (when (or (eq packages t) (memq name packages))
1412 (package--push name (cdr elt)
1413 (if (stringp (cadr (assq name package-load-list)))
1414 "held" "installed")
1415 info-list)))
e91a96fe
CY
1416
1417 ;; Built-in packages:
1418 (dolist (elt package--builtins)
1419 (setq name (car elt))
512e3ae1
CY
1420 (when (and (not (eq name 'emacs)) ; Hide the `emacs' package.
1421 (or (eq packages t) (memq name packages)))
e91a96fe
CY
1422 (package--push name (cdr elt) "built-in" info-list)))
1423
1424 ;; Available and disabled packages:
1425 (dolist (elt package-archive-contents)
1426 (setq name (car elt))
512e3ae1
CY
1427 (when (or (eq packages t) (memq name packages))
1428 (let ((hold (assq name package-load-list)))
1429 (package--push name (cdr elt)
60057926
CY
1430 (cond
1431 ((and hold (null (cadr hold))) "disabled")
1432 ((memq name package-menu--new-package-list) "new")
1433 (t "available"))
512e3ae1 1434 info-list))))
e91a96fe
CY
1435
1436 ;; Obsolete packages:
1437 (dolist (elt package-obsolete-alist)
1438 (dolist (inner-elt (cdr elt))
512e3ae1
CY
1439 (when (or (eq packages t) (memq (car elt) packages))
1440 (package--push (car elt) (cdr inner-elt) "obsolete" info-list))))
e91a96fe
CY
1441
1442 ;; Print the result.
1443 (setq tabulated-list-entries (mapcar 'package-menu--print-info info-list))
1444 (tabulated-list-print remember-pos)))
1445
1446(defun package-menu--print-info (pkg)
1447 "Return a package entry suitable for `tabulated-list-entries'.
1448PKG has the form ((PACKAGE . VERSION) STATUS DOC).
1449Return (KEY [NAME VERSION STATUS DOC]), where KEY is the
1450identifier (NAME . VERSION-LIST)."
1451 (let* ((package (caar pkg))
1452 (version (cdr (car pkg)))
1453 (status (nth 1 pkg))
1454 (doc (or (nth 2 pkg) ""))
1455 (face (cond
1456 ((string= status "built-in") 'font-lock-builtin-face)
1457 ((string= status "available") 'default)
60057926 1458 ((string= status "new") 'bold)
e91a96fe
CY
1459 ((string= status "held") 'font-lock-constant-face)
1460 ((string= status "disabled") 'font-lock-warning-face)
1461 ((string= status "installed") 'font-lock-comment-face)
1462 (t 'font-lock-warning-face)))) ; obsolete.
1463 (list (cons package version)
1464 (vector (list (symbol-name package)
1465 'face 'link
1466 'follow-link t
1467 'package-symbol package
1468 'action 'package-menu-describe-package)
1469 (propertize (package-version-join version)
1470 'font-lock-face face)
1471 (propertize status 'font-lock-face face)
1472 (propertize doc 'font-lock-face face)))))
44198b6e
CY
1473
1474(defun package-menu-refresh ()
ebf662f4
CY
1475 "Download the Emacs Lisp package archive.
1476This fetches the contents of each archive specified in
1477`package-archives', and then refreshes the package menu."
44198b6e 1478 (interactive)
25322144 1479 (unless (derived-mode-p 'package-menu-mode)
187d3296 1480 (error "The current buffer is not a Package Menu"))
44198b6e 1481 (package-refresh-contents)
512e3ae1 1482 (package-menu--generate t t))
44198b6e 1483
e91a96fe
CY
1484(defun package-menu-describe-package (&optional button)
1485 "Describe the current package.
1486If optional arg BUTTON is non-nil, describe its associated package."
44198b6e 1487 (interactive)
e91a96fe
CY
1488 (let ((package (if button (button-get button 'package-symbol)
1489 (car (tabulated-list-get-id)))))
1490 (if package
1491 (describe-package package))))
44198b6e
CY
1492
1493;; fixme numeric argument
4d6769e1 1494(defun package-menu-mark-delete (&optional _num)
44198b6e
CY
1495 "Mark a package for deletion and move to the next line."
1496 (interactive "p")
fb87e0fb 1497 (if (member (package-menu-get-status) '("installed" "obsolete"))
e91a96fe 1498 (tabulated-list-put-tag "D" t)
015eea59 1499 (forward-line)))
44198b6e 1500
4d6769e1 1501(defun package-menu-mark-install (&optional _num)
44198b6e
CY
1502 "Mark a package for installation and move to the next line."
1503 (interactive "p")
60057926 1504 (if (member (package-menu-get-status) '("available" "new"))
e91a96fe 1505 (tabulated-list-put-tag "I" t)
015eea59 1506 (forward-line)))
44198b6e 1507
4d6769e1 1508(defun package-menu-mark-unmark (&optional _num)
44198b6e
CY
1509 "Clear any marks on a package and move to the next line."
1510 (interactive "p")
e91a96fe 1511 (tabulated-list-put-tag " " t))
44198b6e
CY
1512
1513(defun package-menu-backup-unmark ()
1514 "Back up one line and clear any marks on that package."
1515 (interactive)
1516 (forward-line -1)
e91a96fe 1517 (tabulated-list-put-tag " "))
44198b6e
CY
1518
1519(defun package-menu-mark-obsolete-for-deletion ()
1520 "Mark all obsolete packages for deletion."
1521 (interactive)
1522 (save-excursion
1523 (goto-char (point-min))
44198b6e 1524 (while (not (eobp))
25322144 1525 (if (equal (package-menu-get-status) "obsolete")
e91a96fe 1526 (tabulated-list-put-tag "D" t)
44198b6e
CY
1527 (forward-line 1)))))
1528
1529(defun package-menu-quick-help ()
1530 "Show short key binding help for package-menu-mode."
1531 (interactive)
1532 (message "n-ext, i-nstall, d-elete, u-nmark, x-ecute, r-efresh, h-elp"))
1533
cb6c4991
CY
1534(define-obsolete-function-alias
1535 'package-menu-view-commentary 'package-menu-describe-package "24.1")
44198b6e 1536
44198b6e 1537(defun package-menu-get-status ()
25322144
CY
1538 (let* ((pkg (tabulated-list-get-id))
1539 (entry (and pkg (assq pkg tabulated-list-entries))))
1540 (if entry
1541 (aref (cadr entry) 2)
44198b6e
CY
1542 "")))
1543
25322144
CY
1544(defun package-menu--find-upgrades ()
1545 (let (installed available upgrades)
1546 ;; Build list of installed/available packages in this buffer.
1547 (dolist (entry tabulated-list-entries)
1548 ;; ENTRY is ((NAME . VERSION) [NAME VERSION STATUS DOC])
1549 (let ((pkg (car entry))
4d6769e1 1550 (status (aref (cadr entry) 2)))
25322144
CY
1551 (cond ((equal status "installed")
1552 (push pkg installed))
60057926 1553 ((member status '("available" "new"))
25322144
CY
1554 (push pkg available)))))
1555 ;; Loop through list of installed packages, finding upgrades
1556 (dolist (pkg installed)
1557 (let ((avail-pkg (assq (car pkg) available)))
1558 (and avail-pkg
1559 (version-list-< (cdr pkg) (cdr avail-pkg))
1560 (push avail-pkg upgrades))))
1561 upgrades))
1562
1563(defun package-menu-mark-upgrades ()
1564 "Mark all upgradable packages in the Package Menu.
1565For each installed package with a newer version available, place
1566an (I)nstall flag on the available version and a (D)elete flag on
1567the installed version. A subsequent \\[package-menu-execute]
1568call will upgrade the package."
1569 (interactive)
1570 (unless (derived-mode-p 'package-menu-mode)
1571 (error "The current buffer is not a Package Menu"))
1572 (let ((upgrades (package-menu--find-upgrades)))
1573 (if (null upgrades)
1574 (message "No packages to upgrade.")
1575 (widen)
1576 (save-excursion
1577 (goto-char (point-min))
1578 (while (not (eobp))
1579 (let* ((pkg (tabulated-list-get-id))
1580 (upgrade (assq (car pkg) upgrades)))
1581 (cond ((null upgrade)
1582 (forward-line 1))
1583 ((equal pkg upgrade)
1584 (package-menu-mark-install))
1585 (t
1586 (package-menu-mark-delete))))))
1587 (message "%d package%s marked for upgrading."
1588 (length upgrades)
1589 (if (= (length upgrades) 1) "" "s")))))
1590
44198b6e 1591(defun package-menu-execute ()
015eea59
CY
1592 "Perform marked Package Menu actions.
1593Packages marked for installation are downloaded and installed;
1594packages marked for deletion are removed."
44198b6e 1595 (interactive)
25322144 1596 (unless (derived-mode-p 'package-menu-mode)
e91a96fe
CY
1597 (error "The current buffer is not in Package Menu mode"))
1598 (let (install-list delete-list cmd id)
015eea59
CY
1599 (save-excursion
1600 (goto-char (point-min))
1601 (while (not (eobp))
1602 (setq cmd (char-after))
e91a96fe
CY
1603 (unless (eq cmd ?\s)
1604 ;; This is the key (PACKAGE . VERSION-LIST).
1605 (setq id (tabulated-list-get-id))
1606 (cond ((eq cmd ?D)
1607 (push (cons (symbol-name (car id))
1608 (package-version-join (cdr id)))
1609 delete-list))
1610 ((eq cmd ?I)
1611 (push (car id) install-list))))
015eea59 1612 (forward-line)))
25322144
CY
1613 (when install-list
1614 (if (yes-or-no-p
1615 (if (= (length install-list) 1)
1616 (format "Install package `%s'? " (car install-list))
1617 (format "Install these %d packages (%s)? "
1618 (length install-list)
1619 (mapconcat 'symbol-name install-list ", "))))
1620 (mapc 'package-install install-list)))
015eea59
CY
1621 ;; Delete packages, prompting if necessary.
1622 (when delete-list
1623 (if (yes-or-no-p
1624 (if (= (length delete-list) 1)
1625 (format "Delete package `%s-%s'? "
1626 (caar delete-list)
1627 (cdr (car delete-list)))
1628 (format "Delete these %d packages (%s)? "
1629 (length delete-list)
1630 (mapconcat (lambda (elt)
1631 (concat (car elt) "-" (cdr elt)))
1632 delete-list
1633 ", "))))
1634 (dolist (elt delete-list)
1be3ca5a 1635 (condition-case-unless-debug err
015eea59
CY
1636 (package-delete (car elt) (cdr elt))
1637 (error (message (cadr err)))))
1638 (error "Aborted")))
015eea59
CY
1639 ;; If we deleted anything, regenerate `package-alist'. This is done
1640 ;; automatically if we installed a package.
1641 (and delete-list (null install-list)
1642 (package-initialize))
1643 (if (or delete-list install-list)
512e3ae1 1644 (package-menu--generate t t)
015eea59 1645 (message "No operations specified."))))
44198b6e 1646
e91a96fe
CY
1647(defun package-menu--version-predicate (A B)
1648 (let ((vA (or (aref (cadr A) 1) '(0)))
1649 (vB (or (aref (cadr B) 1) '(0))))
1650 (if (version-list-= vA vB)
1651 (package-menu--name-predicate A B)
1652 (version-list-< vA vB))))
1653
1654(defun package-menu--status-predicate (A B)
1655 (let ((sA (aref (cadr A) 2))
1656 (sB (aref (cadr B) 2)))
1657 (cond ((string= sA sB)
1658 (package-menu--name-predicate A B))
60057926
CY
1659 ((string= sA "new") t)
1660 ((string= sB "new") nil)
1661 ((string= sA "available") t)
e91a96fe 1662 ((string= sB "available") nil)
60057926 1663 ((string= sA "installed") t)
e91a96fe 1664 ((string= sB "installed") nil)
60057926 1665 ((string= sA "held") t)
e91a96fe 1666 ((string= sB "held") nil)
60057926 1667 ((string= sA "built-in") t)
e91a96fe 1668 ((string= sB "built-in") nil)
60057926
CY
1669 ((string= sA "obsolete") t)
1670 ((string= sB "obsolete") nil)
e91a96fe
CY
1671 (t (string< sA sB)))))
1672
1673(defun package-menu--description-predicate (A B)
1674 (let ((dA (aref (cadr A) 3))
1675 (dB (aref (cadr B) 3)))
1676 (if (string= dA dB)
1677 (package-menu--name-predicate A B)
1678 (string< dA dB))))
1679
1680(defun package-menu--name-predicate (A B)
1681 (string< (symbol-name (caar A))
1682 (symbol-name (caar B))))
44198b6e
CY
1683
1684;;;###autoload
e91a96fe 1685(defun list-packages (&optional no-fetch)
44198b6e 1686 "Display a list of packages.
e91a96fe
CY
1687This first fetches the updated list of packages before
1688displaying, unless a prefix argument NO-FETCH is specified.
44198b6e 1689The list is displayed in a buffer named `*Packages*'."
e91a96fe
CY
1690 (interactive "P")
1691 (require 'finder-inf nil t)
8a500a91 1692 ;; Initialize the package system if necessary.
4b99edf2
CY
1693 (unless package--initialized
1694 (package-initialize t))
60057926
CY
1695 (let (old-archives new-packages)
1696 (unless no-fetch
1697 ;; Read the locally-cached archive-contents.
1698 (package-read-all-archive-contents)
1699 (setq old-archives package-archive-contents)
1700 ;; Fetch the remote list of packages.
1701 (package-refresh-contents)
1702 ;; Find which packages are new.
1703 (dolist (elt package-archive-contents)
1704 (unless (assq (car elt) old-archives)
1705 (push (car elt) new-packages))))
1706
1707 ;; Generate the Package Menu.
1708 (let ((buf (get-buffer-create "*Packages*")))
1709 (with-current-buffer buf
1710 (package-menu-mode)
1711 (set (make-local-variable 'package-menu--new-package-list)
1712 new-packages)
1713 (package-menu--generate nil t))
1714 ;; The package menu buffer has keybindings. If the user types
1715 ;; `M-x list-packages', that suggests it should become current.
1716 (switch-to-buffer buf))
1717
1718 (let ((upgrades (package-menu--find-upgrades)))
1719 (if upgrades
1720 (message "%d package%s can be upgraded; type `%s' to mark %s for upgrading."
1721 (length upgrades)
1722 (if (= (length upgrades) 1) "" "s")
1723 (substitute-command-keys "\\[package-menu-mark-upgrades]")
1724 (if (= (length upgrades) 1) "it" "them"))))))
44198b6e 1725
cb8759ca 1726;;;###autoload
96ae4c8f 1727(defalias 'package-list-packages 'list-packages)
cb8759ca 1728
512e3ae1
CY
1729;; Used in finder.el
1730(defun package-show-package-list (packages)
1731 "Display PACKAGES in a *Packages* buffer.
1732This is similar to `list-packages', but it does not fetch the
1733updated list of packages, and it only displays packages with
1734names in PACKAGES (which should be a list of symbols)."
1735 (require 'finder-inf nil t)
1736 (let ((buf (get-buffer-create "*Packages*")))
1737 (with-current-buffer buf
1738 (package-menu-mode)
1739 (package-menu--generate nil packages))
1740 (switch-to-buffer buf)))
1741
44198b6e
CY
1742(defun package-list-packages-no-fetch ()
1743 "Display a list of packages.
1744Does not fetch the updated list of packages before displaying.
1745The list is displayed in a buffer named `*Packages*'."
1746 (interactive)
e91a96fe 1747 (list-packages t))
44198b6e 1748
44198b6e
CY
1749(provide 'package)
1750
1751;;; package.el ends here