Modularize add-log-current-defun.
[bpt/emacs.git] / lisp / emacs-lisp / package.el
CommitLineData
44198b6e
CY
1;;; package.el --- Simple package system for Emacs
2
acaf905b 3;; Copyright (C) 2007-2012 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" ())
599
600(defun package-untar-buffer (dir)
44198b6e 601 "Untar the current buffer.
4525ce3e
CY
602This uses `tar-untar-buffer' from Tar mode. All files should
603untar into a directory named DIR; otherwise, signal an error."
44198b6e 604 (require 'tar-mode)
4525ce3e
CY
605 (tar-mode)
606 ;; Make sure everything extracts into DIR.
607 (let ((regexp (concat "\\`" (regexp-quote dir) "/")))
608 (dolist (tar-data tar-parse-info)
609 (unless (string-match regexp (aref tar-data 2))
610 (error "Package does not untar cleanly into directory %s/" dir))))
611 (tar-untar-buffer))
44198b6e 612
292112ed
CY
613(defun package-unpack (package version)
614 (let* ((name (symbol-name package))
615 (dirname (concat name "-" version))
4525ce3e 616 (pkg-dir (expand-file-name dirname package-user-dir)))
44198b6e 617 (make-directory package-user-dir t)
015eea59 618 ;; FIXME: should we delete PKG-DIR if it exists?
44198b6e 619 (let* ((default-directory (file-name-as-directory package-user-dir)))
4525ce3e 620 (package-untar-buffer dirname)
292112ed
CY
621 (package--make-autoloads-and-compile name pkg-dir))))
622
623(defun package--make-autoloads-and-compile (name pkg-dir)
624 "Generate autoloads and do byte-compilation for package named NAME.
625PKG-DIR is the name of the package directory."
626 (package-generate-autoloads name pkg-dir)
627 (let ((load-path (cons pkg-dir load-path)))
628 ;; We must load the autoloads file before byte compiling, in
629 ;; case there are magic cookies to set up non-trivial paths.
630 (load (expand-file-name (concat name "-autoloads") pkg-dir) nil t)
631 (byte-recompile-directory pkg-dir 0 t)))
44198b6e 632
c6affbde 633(defun package--write-file-no-coding (file-name)
bc44bef7 634 (let ((buffer-file-coding-system 'no-conversion))
c6affbde 635 (write-region (point-min) (point-max) file-name)))
bc44bef7 636
44198b6e
CY
637(defun package-unpack-single (file-name version desc requires)
638 "Install the contents of the current buffer as a package."
639 ;; Special case "package".
640 (if (string= file-name "package")
bc44bef7 641 (package--write-file-no-coding
c6affbde 642 (expand-file-name (concat file-name ".el") package-user-dir))
ba08b241
CY
643 (let* ((pkg-dir (expand-file-name (concat file-name "-"
644 (package-version-join
645 (version-to-list version)))
44198b6e
CY
646 package-user-dir))
647 (el-file (expand-file-name (concat file-name ".el") pkg-dir))
648 (pkg-file (expand-file-name (concat file-name "-pkg.el") pkg-dir)))
649 (make-directory pkg-dir t)
c6affbde 650 (package--write-file-no-coding el-file)
44198b6e
CY
651 (let ((print-level nil)
652 (print-length nil))
653 (write-region
654 (concat
655 (prin1-to-string
656 (list 'define-package
657 file-name
658 version
659 desc
660 (list 'quote
661 ;; Turn version lists into string form.
662 (mapcar
663 (lambda (elt)
664 (list (car elt)
015eea59 665 (package-version-join (cadr elt))))
44198b6e
CY
666 requires))))
667 "\n")
668 nil
669 pkg-file
670 nil nil nil 'excl))
292112ed 671 (package--make-autoloads-and-compile file-name pkg-dir))))
44198b6e 672
f561e49a
CY
673(defmacro package--with-work-buffer (location file &rest body)
674 "Run BODY in a buffer containing the contents of FILE at LOCATION.
675LOCATION is the base location of a package archive, and should be
676one of the URLs (or file names) specified in `package-archives'.
677FILE is the name of a file relative to that base location.
678
679This macro retrieves FILE from LOCATION into a temporary buffer,
680and evaluates BODY while that buffer is current. This work
681buffer is killed afterwards. Return the last value in BODY."
da91b5f2 682 `(let* ((http (string-match "\\`https?:" ,location))
f561e49a
CY
683 (buffer
684 (if http
685 (url-retrieve-synchronously (concat ,location ,file))
686 (generate-new-buffer "*package work buffer*"))))
687 (prog1
688 (with-current-buffer buffer
689 (if http
690 (progn (package-handle-response)
691 (re-search-forward "^$" nil 'move)
692 (forward-char)
693 (delete-region (point-min) (point)))
694 (unless (file-name-absolute-p ,location)
695 (error "Archive location %s is not an absolute file name"
696 ,location))
697 (insert-file-contents (expand-file-name ,file ,location)))
698 ,@body)
699 (kill-buffer buffer))))
700
44198b6e 701(defun package-handle-response ()
f561e49a 702 "Handle the response from a `url-retrieve-synchronously' call.
44198b6e
CY
703Parse the HTTP response and throw if an error occurred.
704The url package seems to require extra processing for this.
705This should be called in a `save-excursion', in the download buffer.
706It will move point to somewhere in the headers."
707 ;; We assume HTTP here.
708 (require 'url-http)
709 (let ((response (url-http-parse-response)))
710 (when (or (< response 200) (>= response 300))
44198b6e
CY
711 (error "Error during download request:%s"
712 (buffer-substring-no-properties (point) (progn
713 (end-of-line)
714 (point)))))))
715
716(defun package-download-single (name version desc requires)
717 "Download and install a single-file package."
f561e49a
CY
718 (let ((location (package-archive-base name))
719 (file (concat (symbol-name name) "-" version ".el")))
720 (package--with-work-buffer location file
721 (package-unpack-single (symbol-name name) version desc requires))))
44198b6e
CY
722
723(defun package-download-tar (name version)
724 "Download and install a tar package."
f561e49a
CY
725 (let ((location (package-archive-base name))
726 (file (concat (symbol-name name) "-" version ".tar")))
727 (package--with-work-buffer location file
728 (package-unpack name version))))
44198b6e 729
bc44bef7 730(defun package-installed-p (package &optional min-version)
7ede3b65
CY
731 "Return true if PACKAGE, of MIN-VERSION or newer, is installed.
732MIN-VERSION should be a version list."
a7723be6 733 (unless package--initialized (error "package.el is not yet initialized!"))
44198b6e 734 (let ((pkg-desc (assq package package-alist)))
4b99edf2
CY
735 (if pkg-desc
736 (version-list-<= min-version
737 (package-desc-vers (cdr pkg-desc)))
738 ;; Also check built-in packages.
739 (package-built-in-p package min-version))))
44198b6e 740
96ae4c8f
CY
741(defun package-compute-transaction (package-list requirements)
742 "Return a list of packages to be installed, including PACKAGE-LIST.
743PACKAGE-LIST should be a list of package names (symbols).
744
745REQUIREMENTS should be a list of additional requirements; each
7ede3b65
CY
746element in this list should have the form (PACKAGE VERSION-LIST),
747where PACKAGE is a package name and VERSION-LIST is the required
748version of that package.
96ae4c8f
CY
749
750This function recursively computes the requirements of the
751packages in REQUIREMENTS, and returns a list of all the packages
752that must be installed. Packages that are already installed are
753not included in this list."
44198b6e
CY
754 (dolist (elt requirements)
755 (let* ((next-pkg (car elt))
756 (next-version (cadr elt)))
757 (unless (package-installed-p next-pkg next-version)
758 ;; A package is required, but not installed. It might also be
759 ;; blocked via `package-load-list'.
760 (let ((pkg-desc (assq next-pkg package-archive-contents))
761 hold)
762 (when (setq hold (assq next-pkg package-load-list))
763 (setq hold (cadr hold))
8ac9e529
DH
764 (cond ((eq hold t))
765 ((eq hold nil)
44198b6e
CY
766 (error "Required package '%s' is disabled"
767 (symbol-name next-pkg)))
768 ((null (stringp hold))
769 (error "Invalid element in `package-load-list'"))
148cef8e 770 ((version-list-< (version-to-list hold) next-version)
015eea59 771 (error "Package `%s' held at version %s, \
44198b6e
CY
772but version %s required"
773 (symbol-name next-pkg) hold
774 (package-version-join next-version)))))
775 (unless pkg-desc
015eea59 776 (error "Package `%s-%s' is unavailable"
4b99edf2
CY
777 (symbol-name next-pkg)
778 (package-version-join next-version)))
148cef8e
CY
779 (unless (version-list-<= next-version
780 (package-desc-vers (cdr pkg-desc)))
44198b6e 781 (error
015eea59 782 "Need package `%s-%s', but only %s is available"
44198b6e
CY
783 (symbol-name next-pkg) (package-version-join next-version)
784 (package-version-join (package-desc-vers (cdr pkg-desc)))))
785 ;; Only add to the transaction if we don't already have it.
96ae4c8f 786 (unless (memq next-pkg package-list)
ebf662f4 787 (push next-pkg package-list))
96ae4c8f
CY
788 (setq package-list
789 (package-compute-transaction package-list
44198b6e
CY
790 (package-desc-reqs
791 (cdr pkg-desc))))))))
96ae4c8f 792 package-list)
44198b6e
CY
793
794(defun package-read-from-string (str)
795 "Read a Lisp expression from STR.
796Signal an error if the entire string was not used."
797 (let* ((read-data (read-from-string str))
187d3296
CY
798 (more-left
799 (condition-case nil
800 ;; The call to `ignore' suppresses a compiler warning.
801 (progn (ignore (read-from-string
802 (substring str (cdr read-data))))
803 t)
804 (end-of-file nil))))
44198b6e
CY
805 (if more-left
806 (error "Can't read whole string")
807 (car read-data))))
808
809(defun package--read-archive-file (file)
810 "Re-read archive file FILE, if it exists.
811Will return the data from the file, or nil if the file does not exist.
812Will throw an error if the archive version is too new."
813 (let ((filename (expand-file-name file package-user-dir)))
187d3296
CY
814 (when (file-exists-p filename)
815 (with-temp-buffer
816 (insert-file-contents-literally filename)
817 (let ((contents (read (current-buffer))))
818 (if (> (car contents) package-archive-version)
819 (error "Package archive version %d is higher than %d"
820 (car contents) package-archive-version))
821 (cdr contents))))))
44198b6e 822
bc44bef7 823(defun package-read-all-archive-contents ()
96ae4c8f
CY
824 "Re-read `archive-contents', if it exists.
825If successful, set `package-archive-contents'."
fbe3be3f 826 (setq package-archive-contents nil)
bc44bef7 827 (dolist (archive package-archives)
96ae4c8f 828 (package-read-archive-contents (car archive))))
44198b6e 829
bc44bef7 830(defun package-read-archive-contents (archive)
187d3296
CY
831 "Re-read archive contents for ARCHIVE.
832If successful, set the variable `package-archive-contents'.
bc44bef7 833If the archive version is too new, signal an error."
187d3296
CY
834 ;; Version 1 of 'archive-contents' is identical to our internal
835 ;; representation.
836 (let* ((dir (concat "archives/" archive))
837 (contents-file (concat dir "/archive-contents"))
838 contents)
839 (when (setq contents (package--read-archive-file contents-file))
840 (dolist (package contents)
841 (package--add-to-archive-contents package archive)))))
bc44bef7
PH
842
843(defun package--add-to-archive-contents (package archive)
844 "Add the PACKAGE from the given ARCHIVE if necessary.
845Also, add the originating archive to the end of the package vector."
846 (let* ((name (car package))
25322144
CY
847 (version (package-desc-vers (cdr package)))
848 (entry (cons name
bc44bef7 849 (vconcat (cdr package) (vector archive))))
25322144
CY
850 (existing-package (assq name package-archive-contents)))
851 (cond ((not existing-package)
852 (add-to-list 'package-archive-contents entry))
853 ((version-list-< (package-desc-vers (cdr existing-package))
854 version)
855 ;; Replace the entry with this one.
856 (setq package-archive-contents
857 (cons entry
858 (delq existing-package
859 package-archive-contents)))))))
bc44bef7 860
96ae4c8f
CY
861(defun package-download-transaction (package-list)
862 "Download and install all the packages in PACKAGE-LIST.
863PACKAGE-LIST should be a list of package names (symbols).
864This function assumes that all package requirements in
865PACKAGE-LIST are satisfied, i.e. that PACKAGE-LIST is computed
866using `package-compute-transaction'."
867 (dolist (elt package-list)
44198b6e
CY
868 (let* ((desc (cdr (assq elt package-archive-contents)))
869 ;; As an exception, if package is "held" in
870 ;; `package-load-list', download the held version.
871 (hold (cadr (assq elt package-load-list)))
872 (v-string (or (and (stringp hold) hold)
873 (package-version-join (package-desc-vers desc))))
874 (kind (package-desc-kind desc)))
875 (cond
876 ((eq kind 'tar)
877 (package-download-tar elt v-string))
878 ((eq kind 'single)
879 (package-download-single elt v-string
880 (package-desc-doc desc)
881 (package-desc-reqs desc)))
882 (t
0ce8e868
CY
883 (error "Unknown package kind: %s" (symbol-name kind))))
884 ;; If package A depends on package B, then A may `require' B
885 ;; during byte compilation. So we need to activate B before
886 ;; unpacking A.
887 (package-maybe-load-descriptor (symbol-name elt) v-string
888 package-user-dir)
889 (package-activate elt (version-to-list v-string)))))
44198b6e 890
7254299e
CY
891(defvar package--initialized nil)
892
44198b6e
CY
893;;;###autoload
894(defun package-install (name)
895 "Install the package named NAME.
7254299e
CY
896NAME should be the name of one of the available packages in an
897archive in `package-archives'. Interactively, prompt for NAME."
44198b6e 898 (interactive
7254299e
CY
899 (progn
900 ;; Initialize the package system to get the list of package
901 ;; symbols for completion.
902 (unless package--initialized
903 (package-initialize t))
70550acf
PH
904 (unless package-archive-contents
905 (package-refresh-contents))
7254299e
CY
906 (list (intern (completing-read
907 "Install package: "
908 (mapcar (lambda (elt)
909 (cons (symbol-name (car elt))
910 nil))
911 package-archive-contents)
912 nil t)))))
44198b6e
CY
913 (let ((pkg-desc (assq name package-archive-contents)))
914 (unless pkg-desc
015eea59 915 (error "Package `%s' is not available for installation"
44198b6e 916 (symbol-name name)))
bc44bef7
PH
917 (package-download-transaction
918 (package-compute-transaction (list name)
0ce8e868 919 (package-desc-reqs (cdr pkg-desc))))))
44198b6e 920
ffbf300e
CY
921(defun package-strip-rcs-id (str)
922 "Strip RCS version ID from the version string STR.
44198b6e
CY
923If the result looks like a dotted numeric version, return it.
924Otherwise return nil."
ffbf300e
CY
925 (when str
926 (when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str)
927 (setq str (substring str (match-end 0))))
928 (condition-case nil
929 (if (version-to-list str)
930 str)
931 (error nil))))
44198b6e
CY
932
933(defun package-buffer-info ()
187d3296
CY
934 "Return a vector describing the package in the current buffer.
935The vector has the form
936
937 [FILENAME REQUIRES DESCRIPTION VERSION COMMENTARY]
938
939FILENAME is the file name, a string, sans the \".el\" extension.
7ede3b65
CY
940REQUIRES is a list of requirements, each requirement having the
941 form (NAME VER); NAME is a string and VER is a version list.
187d3296 942DESCRIPTION is the package description, a string.
44198b6e
CY
943VERSION is the version, a string.
944COMMENTARY is the commentary section, a string, or nil if none.
187d3296
CY
945
946If the buffer does not contain a conforming package, signal an
947error. If there is a package, narrow the buffer to the file's
948boundaries."
44198b6e 949 (goto-char (point-min))
f677562b 950 (unless (re-search-forward "^;;; \\([^ ]*\\)\\.el ---[ \t]*\\(.*?\\)[ \t]*\\(-\\*-.*-\\*-[ \t]*\\)?$" nil t)
187d3296
CY
951 (error "Packages lacks a file header"))
952 (let ((file-name (match-string-no-properties 1))
953 (desc (match-string-no-properties 2))
954 (start (line-beginning-position)))
955 (unless (search-forward (concat ";;; " file-name ".el ends here"))
956 (error "Package lacks a terminating comment"))
957 ;; Try to include a trailing newline.
958 (forward-line)
959 (narrow-to-region start (point))
960 (require 'lisp-mnt)
961 ;; Use some headers we've invented to drive the process.
962 (let* ((requires-str (lm-header "package-requires"))
963 (requires (if requires-str
964 (package-read-from-string requires-str)))
965 ;; Prefer Package-Version; if defined, the package author
966 ;; probably wants us to use it. Otherwise try Version.
967 (pkg-version
968 (or (package-strip-rcs-id (lm-header "package-version"))
969 (package-strip-rcs-id (lm-header "version"))))
970 (commentary (lm-commentary)))
971 (unless pkg-version
972 (error
973 "Package lacks a \"Version\" or \"Package-Version\" header"))
974 ;; Turn string version numbers into list form.
975 (setq requires
976 (mapcar
977 (lambda (elt)
978 (list (car elt)
979 (version-to-list (car (cdr elt)))))
980 requires))
981 (vector file-name requires desc pkg-version commentary))))
44198b6e
CY
982
983(defun package-tar-file-info (file)
984 "Find package information for a tar file.
985FILE is the name of the tar file to examine.
986The return result is a vector like `package-buffer-info'."
b511b994
MA
987 (let ((default-directory (file-name-directory file))
988 (file (file-name-nondirectory file)))
4525ce3e
CY
989 (unless (string-match (concat "\\`" package-subdirectory-regexp "\\.tar\\'")
990 file)
b511b994
MA
991 (error "Invalid package name `%s'" file))
992 (let* ((pkg-name (match-string-no-properties 1 file))
993 (pkg-version (match-string-no-properties 2 file))
994 ;; Extract the package descriptor.
995 (pkg-def-contents (shell-command-to-string
996 ;; Requires GNU tar.
997 (concat "tar -xOf " file " "
998
999 pkg-name "-" pkg-version "/"
1000 pkg-name "-pkg.el")))
1001 (pkg-def-parsed (package-read-from-string pkg-def-contents)))
1002 (unless (eq (car pkg-def-parsed) 'define-package)
1003 (error "No `define-package' sexp is present in `%s-pkg.el'" pkg-name))
1004 (let ((name-str (nth 1 pkg-def-parsed))
1005 (version-string (nth 2 pkg-def-parsed))
1006 (docstring (nth 3 pkg-def-parsed))
1007 (requires (nth 4 pkg-def-parsed))
1008 (readme (shell-command-to-string
1009 ;; Requires GNU tar.
1010 (concat "tar -xOf " file " "
1011 pkg-name "-" pkg-version "/README"))))
1012 (unless (equal pkg-version version-string)
1013 (error "Package has inconsistent versions"))
1014 (unless (equal pkg-name name-str)
1015 (error "Package has inconsistent names"))
1016 ;; Kind of a hack.
1017 (if (string-match ": Not found in archive" readme)
1018 (setq readme nil))
1019 ;; Turn string version numbers into list form.
1020 (if (eq (car requires) 'quote)
1021 (setq requires (car (cdr requires))))
1022 (setq requires
1023 (mapcar (lambda (elt)
1024 (list (car elt)
1025 (version-to-list (cadr elt))))
1026 requires))
1027 (vector pkg-name requires docstring version-string readme)))))
44198b6e 1028
187d3296
CY
1029;;;###autoload
1030(defun package-install-from-buffer (pkg-info type)
1031 "Install a package from the current buffer.
1032When called interactively, the current buffer is assumed to be a
1033single .el file that follows the packaging guidelines; see info
1034node `(elisp)Packaging'.
1035
1036When called from Lisp, PKG-INFO is a vector describing the
1037information, of the type returned by `package-buffer-info'; and
1038TYPE is the package type (either `single' or `tar')."
1039 (interactive (list (package-buffer-info) 'single))
44198b6e
CY
1040 (save-excursion
1041 (save-restriction
1042 (let* ((file-name (aref pkg-info 0))
187d3296 1043 (requires (aref pkg-info 1))
44198b6e
CY
1044 (desc (if (string= (aref pkg-info 2) "")
1045 "No description available."
1046 (aref pkg-info 2)))
1047 (pkg-version (aref pkg-info 3)))
1048 ;; Download and install the dependencies.
1049 (let ((transaction (package-compute-transaction nil requires)))
1050 (package-download-transaction transaction))
1051 ;; Install the package itself.
1052 (cond
1053 ((eq type 'single)
1054 (package-unpack-single file-name pkg-version desc requires))
1055 ((eq type 'tar)
1056 (package-unpack (intern file-name) pkg-version))
1057 (t
1058 (error "Unknown type: %s" (symbol-name type))))
1059 ;; Try to activate it.
1060 (package-initialize)))))
1061
44198b6e
CY
1062;;;###autoload
1063(defun package-install-file (file)
1064 "Install a package from a file.
1065The file can either be a tar file or an Emacs Lisp file."
1066 (interactive "fPackage file name: ")
1067 (with-temp-buffer
1068 (insert-file-contents-literally file)
1069 (cond
187d3296
CY
1070 ((string-match "\\.el$" file)
1071 (package-install-from-buffer (package-buffer-info) 'single))
44198b6e 1072 ((string-match "\\.tar$" file)
187d3296 1073 (package-install-from-buffer (package-tar-file-info file) 'tar))
44198b6e
CY
1074 (t (error "Unrecognized extension `%s'" (file-name-extension file))))))
1075
1076(defun package-delete (name version)
015eea59
CY
1077 (let ((dir (package--dir name version)))
1078 (if (string-equal (file-name-directory dir)
1079 (file-name-as-directory
1080 (expand-file-name package-user-dir)))
1081 (progn
1082 (delete-directory dir t t)
1083 (message "Package `%s-%s' deleted." name version))
1084 ;; Don't delete "system" packages
1085 (error "Package `%s-%s' is a system package, not deleting"
1086 name version))))
44198b6e 1087
f561e49a 1088(defun package-archive-base (name)
bc44bef7
PH
1089 "Return the archive containing the package NAME."
1090 (let ((desc (cdr (assq (intern-soft name) package-archive-contents))))
1091 (cdr (assoc (aref desc (- (length desc) 1)) package-archives))))
1092
1093(defun package--download-one-archive (archive file)
f561e49a
CY
1094 "Retrieve an archive file FILE from ARCHIVE, and cache it.
1095ARCHIVE should be a cons cell of the form (NAME . LOCATION),
1096similar to an entry in `package-alist'. Save the cached copy to
1097\"archives/NAME/archive-contents\" in `package-user-dir'."
1098 (let* ((dir (expand-file-name "archives" package-user-dir))
1099 (dir (expand-file-name (car archive) dir)))
1100 (package--with-work-buffer (cdr archive) file
ebf662f4
CY
1101 ;; Read the retrieved buffer to make sure it is valid (e.g. it
1102 ;; may fetch a URL redirect page).
1103 (when (listp (read buffer))
1104 (make-directory dir t)
1105 (setq buffer-file-name (expand-file-name file dir))
1106 (let ((version-control 'never))
f561e49a 1107 (save-buffer))))))
44198b6e 1108
38bb2ca8 1109;;;###autoload
44198b6e
CY
1110(defun package-refresh-contents ()
1111 "Download the ELPA archive description if needed.
ebf662f4
CY
1112This informs Emacs about the latest versions of all packages, and
1113makes them available for download."
44198b6e
CY
1114 (interactive)
1115 (unless (file-exists-p package-user-dir)
1116 (make-directory package-user-dir t))
bc44bef7 1117 (dolist (archive package-archives)
1be3ca5a 1118 (condition-case-unless-debug nil
cb6c4991 1119 (package--download-one-archive archive "archive-contents")
187d3296 1120 (error (message "Failed to download `%s' archive."
cb6c4991 1121 (car archive)))))
bc44bef7 1122 (package-read-all-archive-contents))
44198b6e
CY
1123
1124;;;###autoload
4b99edf2 1125(defun package-initialize (&optional no-activate)
44198b6e 1126 "Load Emacs Lisp packages, and activate them.
4b99edf2
CY
1127The variable `package-load-list' controls which packages to load.
1128If optional arg NO-ACTIVATE is non-nil, don't activate packages."
44198b6e 1129 (interactive)
015eea59
CY
1130 (setq package-alist nil
1131 package-obsolete-alist nil)
44198b6e 1132 (package-load-all-descriptors)
bc44bef7 1133 (package-read-all-archive-contents)
4b99edf2
CY
1134 (unless no-activate
1135 (dolist (elt package-alist)
1136 (package-activate (car elt) (package-desc-vers (cdr elt)))))
1137 (setq package--initialized t))
44198b6e
CY
1138
1139\f
cced7584 1140;;;; Package description buffer.
44198b6e 1141
cced7584
CY
1142;;;###autoload
1143(defun describe-package (package)
1144 "Display the full documentation of PACKAGE (a symbol)."
1145 (interactive
8a500a91
CY
1146 (let* ((guess (function-called-at-point))
1147 packages val)
4b99edf2
CY
1148 (require 'finder-inf nil t)
1149 ;; Load the package list if necessary (but don't activate them).
1150 (unless package--initialized
1151 (package-initialize t))
8a500a91 1152 (setq packages (append (mapcar 'car package-alist)
4b99edf2
CY
1153 (mapcar 'car package-archive-contents)
1154 (mapcar 'car package--builtins)))
cced7584
CY
1155 (unless (memq guess packages)
1156 (setq guess nil))
1157 (setq packages (mapcar 'symbol-name packages))
1158 (setq val
1159 (completing-read (if guess
1160 (format "Describe package (default %s): "
1161 guess)
1162 "Describe package: ")
1163 packages nil t nil nil guess))
cb6c4991 1164 (list (if (equal val "") guess (intern val)))))
4b99edf2
CY
1165 (if (or (null package) (not (symbolp package)))
1166 (message "No package specified")
cced7584
CY
1167 (help-setup-xref (list #'describe-package package)
1168 (called-interactively-p 'interactive))
1169 (with-help-window (help-buffer)
1170 (with-current-buffer standard-output
1171 (describe-package-1 package)))))
1172
1173(defun describe-package-1 (package)
96ae4c8f 1174 (require 'lisp-mnt)
cb6c4991
CY
1175 (let ((package-name (symbol-name package))
1176 (built-in (assq package package--builtins))
1177 desc pkg-dir reqs version installable)
cced7584
CY
1178 (prin1 package)
1179 (princ " is ")
4b99edf2
CY
1180 (cond
1181 ;; Loaded packages are in `package-alist'.
1182 ((setq desc (cdr (assq package package-alist)))
1183 (setq version (package-version-join (package-desc-vers desc)))
1184 (if (setq pkg-dir (package--dir package-name version))
1185 (insert "an installed package.\n\n")
1186 ;; This normally does not happen.
1187 (insert "a deleted package.\n\n")))
1188 ;; Available packages are in `package-archive-contents'.
1189 ((setq desc (cdr (assq package package-archive-contents)))
1190 (setq version (package-version-join (package-desc-vers desc))
8adb4c33 1191 installable t)
4b99edf2
CY
1192 (if built-in
1193 (insert "a built-in package.\n\n")
1194 (insert "an uninstalled package.\n\n")))
1195 (built-in
1196 (setq desc (cdr built-in)
1197 version (package-version-join (package-desc-vers desc)))
1198 (insert "a built-in package.\n\n"))
1199 (t
1200 (insert "an orphan package.\n\n")))
cb6c4991 1201
96ae4c8f 1202 (insert " " (propertize "Status" 'font-lock-face 'bold) ": ")
cb6c4991 1203 (cond (pkg-dir
96ae4c8f
CY
1204 (insert (propertize "Installed"
1205 'font-lock-face 'font-lock-comment-face))
cb6c4991
CY
1206 (insert " in `")
1207 ;; Todo: Add button for uninstalling.
1208 (help-insert-xref-button (file-name-as-directory pkg-dir)
1209 'help-package-def pkg-dir)
4b99edf2
CY
1210 (if built-in
1211 (insert "',\n shadowing a "
1212 (propertize "built-in package"
1213 'font-lock-face 'font-lock-builtin-face)
1214 ".")
1215 (insert "'.")))
cb6c4991 1216 (installable
4b99edf2
CY
1217 (if built-in
1218 (insert (propertize "Built-in." 'font-lock-face 'font-lock-builtin-face)
1219 " Alternate version available -- ")
1220 (insert "Available -- "))
1221 (let ((button-text (if (display-graphic-p) "Install" "[Install]"))
cb6c4991
CY
1222 (button-face (if (display-graphic-p)
1223 '(:box (:line-width 2 :color "dark grey")
1224 :background "light grey"
1225 :foreground "black")
1226 'link)))
4b99edf2 1227 (insert-text-button button-text 'face button-face 'follow-link t
cb6c4991
CY
1228 'package-symbol package
1229 'action 'package-install-button-action)))
1230 (built-in
4b99edf2 1231 (insert (propertize "Built-in." 'font-lock-face 'font-lock-builtin-face)))
cb6c4991
CY
1232 (t (insert "Deleted.")))
1233 (insert "\n")
4b99edf2 1234 (and version (> (length version) 0)
96ae4c8f
CY
1235 (insert " "
1236 (propertize "Version" 'font-lock-face 'bold) ": " version "\n"))
4b99edf2
CY
1237
1238 (setq reqs (if desc (package-desc-reqs desc)))
8adb4c33 1239 (when reqs
96ae4c8f 1240 (insert " " (propertize "Requires" 'font-lock-face 'bold) ": ")
8adb4c33
CY
1241 (let ((first t)
1242 name vers text)
1243 (dolist (req reqs)
1244 (setq name (car req)
1245 vers (cadr req)
1246 text (format "%s-%s" (symbol-name name)
1247 (package-version-join vers)))
1248 (cond (first (setq first nil))
1249 ((>= (+ 2 (current-column) (length text))
1250 (window-width))
1251 (insert ",\n "))
1252 (t (insert ", ")))
1253 (help-insert-xref-button text 'help-package name))
1254 (insert "\n")))
96ae4c8f 1255 (insert " " (propertize "Summary" 'font-lock-face 'bold)
4b99edf2 1256 ": " (if desc (package-desc-doc desc)) "\n\n")
cb6c4991 1257
4b99edf2 1258 (if built-in
96ae4c8f
CY
1259 ;; For built-in packages, insert the commentary.
1260 (let ((fn (locate-file (concat package-name ".el") load-path
1261 load-file-rep-suffixes))
1262 (opoint (point)))
1263 (insert (or (lm-commentary fn) ""))
1264 (save-excursion
1265 (goto-char opoint)
1266 (when (re-search-forward "^;;; Commentary:\n" nil t)
1267 (replace-match ""))
1268 (while (re-search-forward "^\\(;+ ?\\)" nil t)
1269 (replace-match ""))))
1270 (let ((readme (expand-file-name (concat package-name "-readme.txt")
f561e49a
CY
1271 package-user-dir))
1272 readme-string)
96ae4c8f
CY
1273 ;; For elpa packages, try downloading the commentary. If that
1274 ;; fails, try an existing readme file in `package-user-dir'.
f561e49a
CY
1275 (cond ((condition-case nil
1276 (package--with-work-buffer (package-archive-base package)
1277 (concat package-name "-readme.txt")
1278 (setq buffer-file-name
1279 (expand-file-name readme package-user-dir))
1280 (let ((version-control 'never))
1281 (save-buffer))
1282 (setq readme-string (buffer-string))
1283 t)
1284 (error nil))
1285 (insert readme-string))
96ae4c8f
CY
1286 ((file-readable-p readme)
1287 (insert-file-contents readme)
1288 (goto-char (point-max))))))))
cb6c4991
CY
1289
1290(defun package-install-button-action (button)
1291 (let ((package (button-get button 'package-symbol)))
1292 (when (y-or-n-p (format "Install package `%s'? " package))
1293 (package-install package)
1294 (revert-buffer nil t)
1295 (goto-char (point-min)))))
cced7584
CY
1296
1297\f
44198b6e
CY
1298;;;; Package menu mode.
1299
54ea2a0d 1300(defvar package-menu-mode-map
e91a96fe 1301 (let ((map (make-sparse-keymap))
64eba874 1302 (menu-map (make-sparse-keymap "Package")))
e91a96fe 1303 (set-keymap-parent map tabulated-list-mode-map)
8adb4c33 1304 (define-key map "\C-m" 'package-menu-describe-package)
54ea2a0d
JB
1305 (define-key map "u" 'package-menu-mark-unmark)
1306 (define-key map "\177" 'package-menu-backup-unmark)
1307 (define-key map "d" 'package-menu-mark-delete)
1308 (define-key map "i" 'package-menu-mark-install)
25322144 1309 (define-key map "U" 'package-menu-mark-upgrades)
54ea2a0d
JB
1310 (define-key map "r" 'package-menu-refresh)
1311 (define-key map "~" 'package-menu-mark-obsolete-for-deletion)
1312 (define-key map "x" 'package-menu-execute)
1313 (define-key map "h" 'package-menu-quick-help)
cb6c4991 1314 (define-key map "?" 'package-menu-describe-package)
64eba874
DN
1315 (define-key map [menu-bar package-menu] (cons "Package" menu-map))
1316 (define-key menu-map [mq]
1317 '(menu-item "Quit" quit-window
1318 :help "Quit package selection"))
1319 (define-key menu-map [s1] '("--"))
1320 (define-key menu-map [mn]
1321 '(menu-item "Next" next-line
1322 :help "Next Line"))
1323 (define-key menu-map [mp]
1324 '(menu-item "Previous" previous-line
1325 :help "Previous Line"))
1326 (define-key menu-map [s2] '("--"))
1327 (define-key menu-map [mu]
1328 '(menu-item "Unmark" package-menu-mark-unmark
1329 :help "Clear any marks on a package and move to the next line"))
1330 (define-key menu-map [munm]
7cc6e154 1331 '(menu-item "Unmark Backwards" package-menu-backup-unmark
64eba874
DN
1332 :help "Back up one line and clear any marks on that package"))
1333 (define-key menu-map [md]
7cc6e154 1334 '(menu-item "Mark for Deletion" package-menu-mark-delete
64eba874
DN
1335 :help "Mark a package for deletion and move to the next line"))
1336 (define-key menu-map [mi]
7cc6e154 1337 '(menu-item "Mark for Install" package-menu-mark-install
64eba874 1338 :help "Mark a package for installation and move to the next line"))
d770725a 1339 (define-key menu-map [mupgrades]
7cc6e154 1340 '(menu-item "Mark Upgradable Packages" package-menu-mark-upgrades
d770725a 1341 :help "Mark packages that have a newer version for upgrading"))
64eba874
DN
1342 (define-key menu-map [s3] '("--"))
1343 (define-key menu-map [mg]
7cc6e154 1344 '(menu-item "Update Package List" revert-buffer
64eba874
DN
1345 :help "Update the list of packages"))
1346 (define-key menu-map [mr]
7cc6e154 1347 '(menu-item "Refresh Package List" package-menu-refresh
64eba874
DN
1348 :help "Download the ELPA archive"))
1349 (define-key menu-map [s4] '("--"))
1350 (define-key menu-map [mt]
7cc6e154 1351 '(menu-item "Mark Obsolete Packages" package-menu-mark-obsolete-for-deletion
64eba874
DN
1352 :help "Mark all obsolete packages for deletion"))
1353 (define-key menu-map [mx]
7cc6e154 1354 '(menu-item "Execute Actions" package-menu-execute
64eba874
DN
1355 :help "Perform all the marked actions"))
1356 (define-key menu-map [s5] '("--"))
1357 (define-key menu-map [mh]
1358 '(menu-item "Help" package-menu-quick-help
1359 :help "Show short key binding help for package-menu-mode"))
1360 (define-key menu-map [mc]
1361 '(menu-item "View Commentary" package-menu-view-commentary
1362 :help "Display information about this package"))
54ea2a0d 1363 map)
44198b6e
CY
1364 "Local keymap for `package-menu-mode' buffers.")
1365
60057926
CY
1366(defvar package-menu--new-package-list nil
1367 "List of newly-available packages since `list-packages' was last called.")
1368
e91a96fe 1369(define-derived-mode package-menu-mode tabulated-list-mode "Package Menu"
44198b6e
CY
1370 "Major mode for browsing a list of packages.
1371Letters do not insert themselves; instead, they are commands.
1372\\<package-menu-mode-map>
1373\\{package-menu-mode-map}"
e91a96fe
CY
1374 (setq tabulated-list-format [("Package" 18 package-menu--name-predicate)
1375 ("Version" 12 nil)
1376 ("Status" 10 package-menu--status-predicate)
1377 ("Description" 0 nil)])
1378 (setq tabulated-list-padding 2)
1379 (setq tabulated-list-sort-key (cons "Status" nil))
1380 (tabulated-list-init-header))
1381
1382(defmacro package--push (package desc status listname)
1383 "Convenience macro for `package-menu--generate'.
1384If the alist stored in the symbol LISTNAME lacks an entry for a
1385package PACKAGE with descriptor DESC, add one. The alist is
7ede3b65
CY
1386keyed with cons cells (PACKAGE . VERSION-LIST), where PACKAGE is
1387a symbol and VERSION-LIST is a version list."
e91a96fe
CY
1388 `(let* ((version (package-desc-vers ,desc))
1389 (key (cons ,package version)))
1390 (unless (assoc key ,listname)
1391 (push (list key ,status (package-desc-doc ,desc)) ,listname))))
1392
512e3ae1 1393(defun package-menu--generate (remember-pos packages)
e91a96fe 1394 "Populate the Package Menu.
512e3ae1
CY
1395If REMEMBER-POS is non-nil, keep point on the same entry.
1396PACKAGES should be t, which means to display all known packages,
1397or a list of package names (symbols) to display."
e91a96fe 1398 ;; Construct list of ((PACKAGE . VERSION) STATUS DESCRIPTION).
4d6769e1 1399 (let (info-list name)
e91a96fe
CY
1400 ;; Installed packages:
1401 (dolist (elt package-alist)
1402 (setq name (car elt))
512e3ae1
CY
1403 (when (or (eq packages t) (memq name packages))
1404 (package--push name (cdr elt)
1405 (if (stringp (cadr (assq name package-load-list)))
1406 "held" "installed")
1407 info-list)))
e91a96fe
CY
1408
1409 ;; Built-in packages:
1410 (dolist (elt package--builtins)
1411 (setq name (car elt))
512e3ae1
CY
1412 (when (and (not (eq name 'emacs)) ; Hide the `emacs' package.
1413 (or (eq packages t) (memq name packages)))
e91a96fe
CY
1414 (package--push name (cdr elt) "built-in" info-list)))
1415
1416 ;; Available and disabled packages:
1417 (dolist (elt package-archive-contents)
1418 (setq name (car elt))
512e3ae1
CY
1419 (when (or (eq packages t) (memq name packages))
1420 (let ((hold (assq name package-load-list)))
1421 (package--push name (cdr elt)
60057926
CY
1422 (cond
1423 ((and hold (null (cadr hold))) "disabled")
1424 ((memq name package-menu--new-package-list) "new")
1425 (t "available"))
512e3ae1 1426 info-list))))
e91a96fe
CY
1427
1428 ;; Obsolete packages:
1429 (dolist (elt package-obsolete-alist)
1430 (dolist (inner-elt (cdr elt))
512e3ae1
CY
1431 (when (or (eq packages t) (memq (car elt) packages))
1432 (package--push (car elt) (cdr inner-elt) "obsolete" info-list))))
e91a96fe
CY
1433
1434 ;; Print the result.
1435 (setq tabulated-list-entries (mapcar 'package-menu--print-info info-list))
1436 (tabulated-list-print remember-pos)))
1437
1438(defun package-menu--print-info (pkg)
1439 "Return a package entry suitable for `tabulated-list-entries'.
1440PKG has the form ((PACKAGE . VERSION) STATUS DOC).
1441Return (KEY [NAME VERSION STATUS DOC]), where KEY is the
1442identifier (NAME . VERSION-LIST)."
1443 (let* ((package (caar pkg))
1444 (version (cdr (car pkg)))
1445 (status (nth 1 pkg))
1446 (doc (or (nth 2 pkg) ""))
1447 (face (cond
1448 ((string= status "built-in") 'font-lock-builtin-face)
1449 ((string= status "available") 'default)
60057926 1450 ((string= status "new") 'bold)
e91a96fe
CY
1451 ((string= status "held") 'font-lock-constant-face)
1452 ((string= status "disabled") 'font-lock-warning-face)
1453 ((string= status "installed") 'font-lock-comment-face)
1454 (t 'font-lock-warning-face)))) ; obsolete.
1455 (list (cons package version)
1456 (vector (list (symbol-name package)
1457 'face 'link
1458 'follow-link t
1459 'package-symbol package
1460 'action 'package-menu-describe-package)
1461 (propertize (package-version-join version)
1462 'font-lock-face face)
1463 (propertize status 'font-lock-face face)
1464 (propertize doc 'font-lock-face face)))))
44198b6e
CY
1465
1466(defun package-menu-refresh ()
ebf662f4
CY
1467 "Download the Emacs Lisp package archive.
1468This fetches the contents of each archive specified in
1469`package-archives', and then refreshes the package menu."
44198b6e 1470 (interactive)
25322144 1471 (unless (derived-mode-p 'package-menu-mode)
187d3296 1472 (error "The current buffer is not a Package Menu"))
44198b6e 1473 (package-refresh-contents)
512e3ae1 1474 (package-menu--generate t t))
44198b6e 1475
e91a96fe
CY
1476(defun package-menu-describe-package (&optional button)
1477 "Describe the current package.
1478If optional arg BUTTON is non-nil, describe its associated package."
44198b6e 1479 (interactive)
e91a96fe
CY
1480 (let ((package (if button (button-get button 'package-symbol)
1481 (car (tabulated-list-get-id)))))
1482 (if package
1483 (describe-package package))))
44198b6e
CY
1484
1485;; fixme numeric argument
4d6769e1 1486(defun package-menu-mark-delete (&optional _num)
44198b6e
CY
1487 "Mark a package for deletion and move to the next line."
1488 (interactive "p")
fb87e0fb 1489 (if (member (package-menu-get-status) '("installed" "obsolete"))
e91a96fe 1490 (tabulated-list-put-tag "D" t)
015eea59 1491 (forward-line)))
44198b6e 1492
4d6769e1 1493(defun package-menu-mark-install (&optional _num)
44198b6e
CY
1494 "Mark a package for installation and move to the next line."
1495 (interactive "p")
60057926 1496 (if (member (package-menu-get-status) '("available" "new"))
e91a96fe 1497 (tabulated-list-put-tag "I" t)
015eea59 1498 (forward-line)))
44198b6e 1499
4d6769e1 1500(defun package-menu-mark-unmark (&optional _num)
44198b6e
CY
1501 "Clear any marks on a package and move to the next line."
1502 (interactive "p")
e91a96fe 1503 (tabulated-list-put-tag " " t))
44198b6e
CY
1504
1505(defun package-menu-backup-unmark ()
1506 "Back up one line and clear any marks on that package."
1507 (interactive)
1508 (forward-line -1)
e91a96fe 1509 (tabulated-list-put-tag " "))
44198b6e
CY
1510
1511(defun package-menu-mark-obsolete-for-deletion ()
1512 "Mark all obsolete packages for deletion."
1513 (interactive)
1514 (save-excursion
1515 (goto-char (point-min))
44198b6e 1516 (while (not (eobp))
25322144 1517 (if (equal (package-menu-get-status) "obsolete")
e91a96fe 1518 (tabulated-list-put-tag "D" t)
44198b6e
CY
1519 (forward-line 1)))))
1520
1521(defun package-menu-quick-help ()
1522 "Show short key binding help for package-menu-mode."
1523 (interactive)
1524 (message "n-ext, i-nstall, d-elete, u-nmark, x-ecute, r-efresh, h-elp"))
1525
cb6c4991
CY
1526(define-obsolete-function-alias
1527 'package-menu-view-commentary 'package-menu-describe-package "24.1")
44198b6e 1528
44198b6e 1529(defun package-menu-get-status ()
25322144
CY
1530 (let* ((pkg (tabulated-list-get-id))
1531 (entry (and pkg (assq pkg tabulated-list-entries))))
1532 (if entry
1533 (aref (cadr entry) 2)
44198b6e
CY
1534 "")))
1535
25322144
CY
1536(defun package-menu--find-upgrades ()
1537 (let (installed available upgrades)
1538 ;; Build list of installed/available packages in this buffer.
1539 (dolist (entry tabulated-list-entries)
1540 ;; ENTRY is ((NAME . VERSION) [NAME VERSION STATUS DOC])
1541 (let ((pkg (car entry))
4d6769e1 1542 (status (aref (cadr entry) 2)))
25322144
CY
1543 (cond ((equal status "installed")
1544 (push pkg installed))
60057926 1545 ((member status '("available" "new"))
25322144
CY
1546 (push pkg available)))))
1547 ;; Loop through list of installed packages, finding upgrades
1548 (dolist (pkg installed)
1549 (let ((avail-pkg (assq (car pkg) available)))
1550 (and avail-pkg
1551 (version-list-< (cdr pkg) (cdr avail-pkg))
1552 (push avail-pkg upgrades))))
1553 upgrades))
1554
1555(defun package-menu-mark-upgrades ()
1556 "Mark all upgradable packages in the Package Menu.
1557For each installed package with a newer version available, place
1558an (I)nstall flag on the available version and a (D)elete flag on
1559the installed version. A subsequent \\[package-menu-execute]
1560call will upgrade the package."
1561 (interactive)
1562 (unless (derived-mode-p 'package-menu-mode)
1563 (error "The current buffer is not a Package Menu"))
1564 (let ((upgrades (package-menu--find-upgrades)))
1565 (if (null upgrades)
1566 (message "No packages to upgrade.")
1567 (widen)
1568 (save-excursion
1569 (goto-char (point-min))
1570 (while (not (eobp))
1571 (let* ((pkg (tabulated-list-get-id))
1572 (upgrade (assq (car pkg) upgrades)))
1573 (cond ((null upgrade)
1574 (forward-line 1))
1575 ((equal pkg upgrade)
1576 (package-menu-mark-install))
1577 (t
1578 (package-menu-mark-delete))))))
1579 (message "%d package%s marked for upgrading."
1580 (length upgrades)
1581 (if (= (length upgrades) 1) "" "s")))))
1582
44198b6e 1583(defun package-menu-execute ()
015eea59
CY
1584 "Perform marked Package Menu actions.
1585Packages marked for installation are downloaded and installed;
1586packages marked for deletion are removed."
44198b6e 1587 (interactive)
25322144 1588 (unless (derived-mode-p 'package-menu-mode)
e91a96fe
CY
1589 (error "The current buffer is not in Package Menu mode"))
1590 (let (install-list delete-list cmd id)
015eea59
CY
1591 (save-excursion
1592 (goto-char (point-min))
1593 (while (not (eobp))
1594 (setq cmd (char-after))
e91a96fe
CY
1595 (unless (eq cmd ?\s)
1596 ;; This is the key (PACKAGE . VERSION-LIST).
1597 (setq id (tabulated-list-get-id))
1598 (cond ((eq cmd ?D)
1599 (push (cons (symbol-name (car id))
1600 (package-version-join (cdr id)))
1601 delete-list))
1602 ((eq cmd ?I)
1603 (push (car id) install-list))))
015eea59 1604 (forward-line)))
25322144
CY
1605 (when install-list
1606 (if (yes-or-no-p
1607 (if (= (length install-list) 1)
1608 (format "Install package `%s'? " (car install-list))
1609 (format "Install these %d packages (%s)? "
1610 (length install-list)
1611 (mapconcat 'symbol-name install-list ", "))))
1612 (mapc 'package-install install-list)))
015eea59
CY
1613 ;; Delete packages, prompting if necessary.
1614 (when delete-list
1615 (if (yes-or-no-p
1616 (if (= (length delete-list) 1)
1617 (format "Delete package `%s-%s'? "
1618 (caar delete-list)
1619 (cdr (car delete-list)))
1620 (format "Delete these %d packages (%s)? "
1621 (length delete-list)
1622 (mapconcat (lambda (elt)
1623 (concat (car elt) "-" (cdr elt)))
1624 delete-list
1625 ", "))))
1626 (dolist (elt delete-list)
1be3ca5a 1627 (condition-case-unless-debug err
015eea59
CY
1628 (package-delete (car elt) (cdr elt))
1629 (error (message (cadr err)))))
1630 (error "Aborted")))
015eea59
CY
1631 ;; If we deleted anything, regenerate `package-alist'. This is done
1632 ;; automatically if we installed a package.
1633 (and delete-list (null install-list)
1634 (package-initialize))
1635 (if (or delete-list install-list)
512e3ae1 1636 (package-menu--generate t t)
015eea59 1637 (message "No operations specified."))))
44198b6e 1638
e91a96fe
CY
1639(defun package-menu--version-predicate (A B)
1640 (let ((vA (or (aref (cadr A) 1) '(0)))
1641 (vB (or (aref (cadr B) 1) '(0))))
1642 (if (version-list-= vA vB)
1643 (package-menu--name-predicate A B)
1644 (version-list-< vA vB))))
1645
1646(defun package-menu--status-predicate (A B)
1647 (let ((sA (aref (cadr A) 2))
1648 (sB (aref (cadr B) 2)))
1649 (cond ((string= sA sB)
1650 (package-menu--name-predicate A B))
60057926
CY
1651 ((string= sA "new") t)
1652 ((string= sB "new") nil)
1653 ((string= sA "available") t)
e91a96fe 1654 ((string= sB "available") nil)
60057926 1655 ((string= sA "installed") t)
e91a96fe 1656 ((string= sB "installed") nil)
60057926 1657 ((string= sA "held") t)
e91a96fe 1658 ((string= sB "held") nil)
60057926 1659 ((string= sA "built-in") t)
e91a96fe 1660 ((string= sB "built-in") nil)
60057926
CY
1661 ((string= sA "obsolete") t)
1662 ((string= sB "obsolete") nil)
e91a96fe
CY
1663 (t (string< sA sB)))))
1664
1665(defun package-menu--description-predicate (A B)
1666 (let ((dA (aref (cadr A) 3))
1667 (dB (aref (cadr B) 3)))
1668 (if (string= dA dB)
1669 (package-menu--name-predicate A B)
1670 (string< dA dB))))
1671
1672(defun package-menu--name-predicate (A B)
1673 (string< (symbol-name (caar A))
1674 (symbol-name (caar B))))
44198b6e
CY
1675
1676;;;###autoload
e91a96fe 1677(defun list-packages (&optional no-fetch)
44198b6e 1678 "Display a list of packages.
e91a96fe
CY
1679This first fetches the updated list of packages before
1680displaying, unless a prefix argument NO-FETCH is specified.
44198b6e 1681The list is displayed in a buffer named `*Packages*'."
e91a96fe
CY
1682 (interactive "P")
1683 (require 'finder-inf nil t)
8a500a91 1684 ;; Initialize the package system if necessary.
4b99edf2
CY
1685 (unless package--initialized
1686 (package-initialize t))
60057926
CY
1687 (let (old-archives new-packages)
1688 (unless no-fetch
1689 ;; Read the locally-cached archive-contents.
1690 (package-read-all-archive-contents)
1691 (setq old-archives package-archive-contents)
1692 ;; Fetch the remote list of packages.
1693 (package-refresh-contents)
1694 ;; Find which packages are new.
1695 (dolist (elt package-archive-contents)
1696 (unless (assq (car elt) old-archives)
1697 (push (car elt) new-packages))))
1698
1699 ;; Generate the Package Menu.
1700 (let ((buf (get-buffer-create "*Packages*")))
1701 (with-current-buffer buf
1702 (package-menu-mode)
1703 (set (make-local-variable 'package-menu--new-package-list)
1704 new-packages)
1705 (package-menu--generate nil t))
1706 ;; The package menu buffer has keybindings. If the user types
1707 ;; `M-x list-packages', that suggests it should become current.
1708 (switch-to-buffer buf))
1709
1710 (let ((upgrades (package-menu--find-upgrades)))
1711 (if upgrades
1712 (message "%d package%s can be upgraded; type `%s' to mark %s for upgrading."
1713 (length upgrades)
1714 (if (= (length upgrades) 1) "" "s")
1715 (substitute-command-keys "\\[package-menu-mark-upgrades]")
1716 (if (= (length upgrades) 1) "it" "them"))))))
44198b6e 1717
cb8759ca 1718;;;###autoload
96ae4c8f 1719(defalias 'package-list-packages 'list-packages)
cb8759ca 1720
512e3ae1
CY
1721;; Used in finder.el
1722(defun package-show-package-list (packages)
1723 "Display PACKAGES in a *Packages* buffer.
1724This is similar to `list-packages', but it does not fetch the
1725updated list of packages, and it only displays packages with
1726names in PACKAGES (which should be a list of symbols)."
1727 (require 'finder-inf nil t)
1728 (let ((buf (get-buffer-create "*Packages*")))
1729 (with-current-buffer buf
1730 (package-menu-mode)
1731 (package-menu--generate nil packages))
1732 (switch-to-buffer buf)))
1733
44198b6e
CY
1734(defun package-list-packages-no-fetch ()
1735 "Display a list of packages.
1736Does not fetch the updated list of packages before displaying.
1737The list is displayed in a buffer named `*Packages*'."
1738 (interactive)
e91a96fe 1739 (list-packages t))
44198b6e 1740
44198b6e
CY
1741(provide 'package)
1742
1743;;; package.el ends here