Mercurial > hg > xemacs-beta
comparison lisp/packages.el @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | abe6d1db359e |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 ;;; packages.el --- Low level support for XEmacs packages | |
2 | |
3 ;; Copyright (C) 1997 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Steven L Baur <steve@xemacs.org> | |
6 ;; Maintainer: Steven L Baur <steve@xemacs.org> | |
7 ;; Keywords: internal, lisp, dumped | |
8 | |
9 ;; This file is part of XEmacs. | |
10 | |
11 ;; XEmacs is free software; you can redistribute it and/or modify it | |
12 ;; under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; XEmacs is distributed in the hope that it will be useful, but | |
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 ;; General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
24 ;; 02111-1307, USA. | |
25 | |
26 ;;; Synched up with: Not in FSF | |
27 | |
28 ;;; Commentary: | |
29 | |
30 ;; This file is dumped with XEmacs. | |
31 | |
32 ;; This file provides low level facilities for XEmacs startup -- | |
33 ;; particularly regarding the package setup. This code has to run in | |
34 ;; what we call "bare temacs" -- i.e. XEmacs without the usual Lisp | |
35 ;; environment. Pay special attention: | |
36 | |
37 ;; - not to use the `lambda' macro. Use #'(lambda ...) instead. | |
38 ;; (this goes for any package loaded before `subr.el'.) | |
39 ;; | |
40 ;; - not to use macros, because they are not yet available (and this | |
41 ;; file must be loadable uncompiled.) This rules out CL-style | |
42 ;; macros like `when', for instance. | |
43 ;; | |
44 ;; - not to use `defcustom'. If you must add user-customizable | |
45 ;; variables here, use `defvar', and add the variable to | |
46 ;; `cus-start.el'. | |
47 | |
48 ;; Because of all this, make sure that the stuff you put here really | |
49 ;; belongs here. | |
50 | |
51 ;; This file requires find-paths.el. | |
52 | |
53 ;;; Code: | |
54 | |
55 ;;; Package versioning | |
56 | |
57 (defvar packages-package-list nil | |
58 "Database of loaded packages and version numbers") | |
59 | |
60 (defvar packages-hierarchy-depth 1 | |
61 "Depth of package hierarchies.") | |
62 | |
63 (defvar packages-load-path-depth 1 | |
64 "Depth of load-path search in package hierarchies.") | |
65 | |
66 (defvar packages-data-path-depth 1 | |
67 "Depth of data-path search in package hierarchies.") | |
68 | |
69 (defvar early-packages nil | |
70 "Packages early in the load path.") | |
71 | |
72 (defvar early-package-load-path nil | |
73 "Load path for packages early in the load path.") | |
74 | |
75 (defvar late-packages nil | |
76 "Packages late in the load path.") | |
77 | |
78 (defvar late-package-load-path nil | |
79 "Load path for packages late in the load path.") | |
80 | |
81 (defvar last-packages nil | |
82 "Packages last in the load path.") | |
83 | |
84 (defvar last-package-load-path nil | |
85 "Load path for packages last in the load path.") | |
86 | |
87 (defun packages-compute-package-locations (user-init-directory) | |
88 "Compute locations of the various package directories. | |
89 This is a list each of whose elements describes one directory. | |
90 A directory description is a three-element list. | |
91 The first element is either an absolute path or a subdirectory | |
92 in the XEmacs hierarchy. | |
93 The second component is one of the symbols EARLY, LATE, LAST, | |
94 depending on the load-path segment the hierarchy is supposed to | |
95 show up in. | |
96 The third component is a thunk which, if it returns NIL, causes | |
97 the directory to be ignored." | |
98 (list | |
99 (list (paths-construct-path (list user-init-directory "mule-packages")) | |
100 'early #'(lambda () (featurep 'mule))) | |
101 (list (paths-construct-path (list user-init-directory "xemacs-packages")) | |
102 'early #'(lambda () t)) | |
103 (list "site-packages" 'late #'(lambda () t)) | |
104 (list "infodock-packages" 'late #'(lambda () (featurep 'infodock))) | |
105 (list "mule-packages" 'late #'(lambda () (featurep 'mule))) | |
106 (list "xemacs-packages" 'late #'(lambda () t)))) | |
107 | |
108 (defun package-get-key-1 (info key) | |
109 "Locate keyword `key' in list." | |
110 (cond ((null info) | |
111 nil) | |
112 ((eq (car info) key) | |
113 (nth 1 info)) | |
114 (t (package-get-key-1 (cddr info) key)))) | |
115 | |
116 (defun package-get-key (name key) | |
117 "Get info `key' from package `name'." | |
118 (let ((info (assq name packages-package-list))) | |
119 (when info | |
120 (package-get-key-1 (cdr info) key)))) | |
121 | |
122 (defun package-provide (name &rest attributes) | |
123 (let ((info (if (and attributes (floatp (car attributes))) | |
124 (list :version (car attributes)) | |
125 attributes))) | |
126 (setq packages-package-list | |
127 (cons (cons name info) (remassq name packages-package-list))))) | |
128 | |
129 (defun package-require (name version) | |
130 (let ((pkg (assq name packages-package-list))) | |
131 (cond ((null pkg) | |
132 (error "Package %s has not been loaded into this XEmacsen" | |
133 name)) | |
134 ((< (package-get-key name :version) version) | |
135 (error "Need version %g of package %s, got version %g" | |
136 version name (cdr pkg))) | |
137 (t t)))) | |
138 | |
139 (defun package-delete-name (name) | |
140 (let (pkg) | |
141 ;; Delete ALL versions of package. | |
142 ;; This is pretty memory-intensive, as we use copy-alist when deleting | |
143 ;; package entries, to prevent side-effects in functions that call this | |
144 ;; one. | |
145 (while (setq pkg (assq name packages-package-list)) | |
146 (setq packages-package-list (delete pkg (copy-alist | |
147 packages-package-list))) | |
148 ) | |
149 )) | |
150 | |
151 ;;; Build time stuff | |
152 | |
153 (defvar autoload-file-name "auto-autoloads.el" | |
154 "Filename that autoloads are expected to be found in.") | |
155 | |
156 (defvar packages-hardcoded-lisp | |
157 '( | |
158 ;; Nothing at this time | |
159 ) | |
160 "Lisp packages that are always dumped with XEmacs. | |
161 This includes every package that is loaded directly by a package listed | |
162 in dumped-lisp.el and is not itself listed.") | |
163 | |
164 (defvar packages-useful-lisp | |
165 '("bytecomp" | |
166 "byte-optimize" | |
167 "shadow" | |
168 "cl-macs") | |
169 "Lisp packages that need early byte compilation.") | |
170 | |
171 (defvar packages-unbytecompiled-lisp | |
172 '("paths.el" | |
173 "dumped-lisp.el" | |
174 "dumped-pkg-lisp.el" | |
175 "version.el" | |
176 "very-early-lisp.el") | |
177 "Lisp packages that should not be byte compiled.") | |
178 | |
179 | |
180 ;; Copied from help.el, could possibly move it to here permanently. | |
181 ;; Unlike the FSF version, our `locate-library' uses the `locate-file' | |
182 ;; primitive, which should make it lightning-fast. | |
183 | |
184 (defun locate-library (library &optional nosuffix path interactive-call) | |
185 "Show the precise file name of Emacs library LIBRARY. | |
186 This command searches the directories in `load-path' like `M-x load-library' | |
187 to find the file that `M-x load-library RET LIBRARY RET' would load. | |
188 Optional second arg NOSUFFIX non-nil means don't add suffixes `.elc' or `.el' | |
189 to the specified name LIBRARY. | |
190 | |
191 If the optional third arg PATH is specified, that list of directories | |
192 is used instead of `load-path'." | |
193 (interactive (list (read-string "Locate library: ") | |
194 nil nil | |
195 t)) | |
196 (let ((result | |
197 (locate-file | |
198 library | |
199 (or path load-path) | |
200 (cond ((or (rassq 'jka-compr-handler file-name-handler-alist) | |
201 (and (boundp 'find-file-hooks) | |
202 (member 'crypt-find-file-hook find-file-hooks))) | |
203 ;; Compression involved. | |
204 (if nosuffix | |
205 '("" ".gz" ".Z") | |
206 '(".elc" ".elc.gz" "elc.Z" ".el" ".el.gz" ".el.Z" "" ".gz" ".Z"))) | |
207 (t | |
208 ;; No compression. | |
209 (if nosuffix | |
210 "" | |
211 '(".elc" ".el" ""))))))) | |
212 (and interactive-call | |
213 (if result | |
214 (message "Library is file %s" result) | |
215 (message "No library %s in search path" library))) | |
216 result)) | |
217 | |
218 (defun packages-add-suffix (str) | |
219 (if (null (string-match "\\.el\\'" str)) | |
220 (concat str ".elc") | |
221 str)) | |
222 | |
223 (defun packages-list-autoloads-path () | |
224 "List autoloads from precomputed load-path." | |
225 (let ((path load-path) | |
226 autoloads) | |
227 (while path | |
228 (if (file-exists-p (concat (car path) | |
229 autoload-file-name)) | |
230 (setq autoloads (cons (concat (car path) | |
231 autoload-file-name) | |
232 autoloads))) | |
233 (setq path (cdr path))) | |
234 autoloads)) | |
235 | |
236 (defun packages-list-autoloads (source-directory) | |
237 "List autoload files in (what will be) the normal lisp search path. | |
238 This function is used during build to find where the global symbol files so | |
239 they can be perused for their useful information." | |
240 (let ((files (directory-files (file-name-as-directory source-directory) | |
241 t ".*")) | |
242 file autolist) | |
243 ;; (print (prin1-to-string source-directory)) | |
244 ;; (print (prin1-to-string files)) | |
245 (while (setq file (car-safe files)) | |
246 (if (and (file-directory-p file) | |
247 (file-exists-p (concat (file-name-as-directory file) | |
248 autoload-file-name))) | |
249 (setq autolist (cons (concat (file-name-as-directory file) | |
250 autoload-file-name) | |
251 autolist))) | |
252 (setq files (cdr files))) | |
253 autolist)) | |
254 | |
255 ;; The following function cannot be called from a bare temacs | |
256 (defun packages-new-autoloads () | |
257 "Return autoloads files that have been added or modified since XEmacs dump." | |
258 (require 'loadhist) | |
259 (let ((me (concat invocation-directory invocation-name)) | |
260 (path load-path) | |
261 result dir) | |
262 (while path | |
263 (setq dir (file-truename (car path))) | |
264 (let ((autoload-file (file-name-sans-extension (concat | |
265 dir | |
266 autoload-file-name)))) | |
267 ;; Check for: | |
268 ;; 1. An auto-autoload file that hasn't provided a feature (because | |
269 ;; it has been installed since XEmacs was dumped). | |
270 ;; 2. auto-autoload.el being newer than the executable | |
271 ;; 3. auto-autoload.elc being newer than the executable (the .el | |
272 ;; could be missing or compressed) | |
273 (when (or (and (null (file-provides autoload-file)) | |
274 (or (file-exists-p (concat autoload-file ".elc")) | |
275 (file-exists-p (concat autoload-file ".el")))) | |
276 (and (file-newer-than-file-p (concat autoload-file ".el") me) | |
277 (setq autoload-file (concat autoload-file ".el"))) | |
278 (and (file-newer-than-file-p (concat autoload-file | |
279 ".elc") | |
280 me) | |
281 (setq autoload-file (concat autoload-file ".elc")))) | |
282 (push autoload-file result))) | |
283 (setq path (cdr path))) | |
284 result)) | |
285 | |
286 ;; The following function cannot be called from a bare temacs | |
287 (defun packages-reload-autoloads () | |
288 "Reload new or updated auto-autoloads files. | |
289 This is an extremely dangerous function to call after the user-init-files | |
290 is run. Don't call it or you'll be sorry." | |
291 (let ((autoload-list (packages-new-autoloads))) | |
292 (while autoload-list | |
293 (let* ((autoload-file (car autoload-list)) | |
294 (feature (car-safe (file-provides autoload-file)))) | |
295 (when feature | |
296 ;; (message "(unload-feature %S)" feature) | |
297 (unload-feature feature)) | |
298 (condition-case nil | |
299 (load autoload-file) | |
300 (t nil))) | |
301 (setq autoload-list (cdr autoload-list))))) | |
302 | |
303 ;; Data-directory is really a list now. Provide something to search it for | |
304 ;; directories. | |
305 | |
306 (defun locate-data-directory-list (name &optional dir-list) | |
307 "Locate the matching list of directories in a search path DIR-LIST. | |
308 If no DIR-LIST is supplied, it defaults to `data-directory-list'." | |
309 (unless dir-list | |
310 (setq dir-list data-directory-list)) | |
311 (let (found found-dir found-dir-list) | |
312 (while dir-list | |
313 (setq found (file-name-as-directory (concat (car dir-list) name)) | |
314 found-dir (file-directory-p found)) | |
315 (and found-dir | |
316 (setq found-dir-list (cons found found-dir-list))) | |
317 (setq dir-list (cdr dir-list))) | |
318 (nreverse found-dir-list))) | |
319 | |
320 ;; Data-directory is really a list now. Provide something to search it for | |
321 ;; a directory. | |
322 | |
323 (defun locate-data-directory (name &optional dir-list) | |
324 "Locate a directory in a search path DIR-LIST (a list of directories). | |
325 If no DIR-LIST is supplied, it defaults to `data-directory-list'." | |
326 (unless dir-list | |
327 (setq dir-list data-directory-list)) | |
328 (let (found found-dir) | |
329 (while (and (null found-dir) dir-list) | |
330 (setq found (file-name-as-directory (concat (car dir-list) name)) | |
331 found-dir (file-directory-p found)) | |
332 (or found-dir | |
333 (setq found nil)) | |
334 (setq dir-list (cdr dir-list))) | |
335 found)) | |
336 | |
337 ;; Data-directory is really a list now. Provide something to search it for | |
338 ;; files. | |
339 | |
340 (defun locate-data-file (name &optional dir-list) | |
341 "Locate a file in a search path DIR-LIST (a list of directories). | |
342 If no DIR-LIST is supplied, it defaults to `data-directory-list'. | |
343 This function is basically a wrapper over `locate-file'." | |
344 (locate-file name (or dir-list data-directory-list))) | |
345 | |
346 ;; Path setup | |
347 | |
348 (defun packages-find-package-directories (roots base) | |
349 "Find a set of package directories." | |
350 ;; make sure paths-find-version-directory and paths-find-site-directory | |
351 ;; don't both pick up version-independent directories ... | |
352 (let ((version-directory (paths-find-version-directory roots base nil nil t)) | |
353 (site-directory (paths-find-site-directory roots base))) | |
354 (paths-uniq-append | |
355 (and version-directory (list version-directory)) | |
356 (and site-directory (list site-directory))))) | |
357 | |
358 (defvar packages-special-base-regexp "^\\(etc\\|info\\|lisp\\|lib-src\\|bin\\|pkginfo\\)$" | |
359 "Special subdirectories of packages.") | |
360 | |
361 (defvar packages-no-package-hierarchy-regexp | |
362 (concat "\\(" paths-version-control-filename-regexp "\\)" | |
363 "\\|" | |
364 "\\(" packages-special-base-regexp "\\)") | |
365 "Directories which can't be the roots of package hierarchies.") | |
366 | |
367 (defun packages-find-packages-in-directories (directories) | |
368 "Find all packages underneath directories in DIRECTORIES." | |
369 (paths-find-recursive-path directories | |
370 packages-hierarchy-depth | |
371 packages-no-package-hierarchy-regexp)) | |
372 | |
373 (defun packages-split-path (path) | |
374 "Split PATH at \"\", return pair with two components. | |
375 The second component is shared with PATH." | |
376 (let ((reverse-tail '()) | |
377 (rest path)) | |
378 (while (and rest (null (string-equal "" (car rest)))) | |
379 (setq reverse-tail (cons (car rest) reverse-tail)) | |
380 (setq rest (cdr rest))) | |
381 (if (null rest) | |
382 (cons path nil) | |
383 (cons (nreverse reverse-tail) (cdr rest))))) | |
384 | |
385 (defun packages-split-package-path (package-path) | |
386 "Split up PACKAGE-PATH into early, late and last components. | |
387 The separation is by \"\" components. | |
388 This returns (LIST EARLY-PACKAGES LATE-PACKAGES LAST-PACKAGES)." | |
389 ;; When in doubt, it's late | |
390 (let* ((stuff (packages-split-path package-path)) | |
391 (early (and (cdr stuff) (car stuff))) | |
392 (late+last (or (cdr stuff) (car stuff))) | |
393 (stuff (packages-split-path late+last)) | |
394 (late (car stuff)) | |
395 (last (cdr stuff))) | |
396 (list (packages-find-packages-in-directories early) | |
397 (packages-find-packages-in-directories late) | |
398 (packages-find-packages-in-directories last)))) | |
399 | |
400 (defun packages-deconstruct (list consumer) | |
401 "Deconstruct LIST and feed it to CONSUMER." | |
402 (apply consumer list)) | |
403 | |
404 (defun packages-find-packages-by-name (roots name) | |
405 "Find a package hierarchy by its name." | |
406 (packages-find-packages-in-directories | |
407 (if (and (file-name-absolute-p name) | |
408 (file-name-directory (expand-file-name name))) | |
409 (list (file-name-as-directory (expand-file-name name))) | |
410 (packages-find-package-directories roots name)))) | |
411 | |
412 (defun packages-find-packages-at-time | |
413 (roots package-locations time &optional default) | |
414 "Find packages at given time. | |
415 For the format of PACKAGE-LOCATIONS, see the global variable of the same name. | |
416 TIME is either 'EARLY, 'LATE, or 'LAST. | |
417 DEFAULT is a default list of packages." | |
418 (or default | |
419 (let ((packages '())) | |
420 (while package-locations | |
421 (packages-deconstruct | |
422 (car package-locations) | |
423 #'(lambda (name a-time thunk) | |
424 (if (and (eq time a-time) | |
425 (funcall thunk)) | |
426 (setq packages | |
427 (nconc packages | |
428 (packages-find-packages-by-name roots name)))))) | |
429 (setq package-locations (cdr package-locations))) | |
430 packages))) | |
431 | |
432 (defun packages-find-packages (roots package-locations) | |
433 "Find the packages." | |
434 (let ((envvar-value (getenv "EMACSPACKAGEPATH"))) | |
435 (if envvar-value | |
436 (packages-split-package-path (paths-decode-directory-path envvar-value)) | |
437 (packages-deconstruct | |
438 (packages-split-package-path configure-package-path) | |
439 #'(lambda (configure-early-packages | |
440 configure-late-packages | |
441 configure-last-packages) | |
442 (list (packages-find-packages-at-time roots package-locations 'early | |
443 configure-early-packages) | |
444 (packages-find-packages-at-time roots package-locations 'late | |
445 configure-late-packages) | |
446 (packages-find-packages-at-time roots package-locations 'last | |
447 configure-last-packages))))))) | |
448 | |
449 (defun packages-find-package-library-path (packages suffixes) | |
450 "Construct a path into a component of the packages hierarchy. | |
451 PACKAGES is a list of package directories. | |
452 SUFFIXES is a list of names of package subdirectories to look for." | |
453 (let ((directories | |
454 (apply | |
455 #'nconc | |
456 (mapcar #'(lambda (package) | |
457 (mapcar #'(lambda (suffix) | |
458 (file-name-as-directory (concat package suffix))) | |
459 suffixes)) | |
460 packages)))) | |
461 (paths-directories-which-exist directories))) | |
462 | |
463 (defun packages-find-package-load-path (packages) | |
464 "Construct the load-path component for packages. | |
465 PACKAGES is a list of package directories." | |
466 (paths-find-recursive-load-path | |
467 (packages-find-package-library-path packages | |
468 '("lisp")) | |
469 packages-load-path-depth)) | |
470 | |
471 (defun packages-find-package-exec-path (packages) | |
472 "Construct the exec-path component for packages. | |
473 PACKAGES is a list of package directories." | |
474 (packages-find-package-library-path packages | |
475 (list (paths-construct-path | |
476 (list "bin" system-configuration)) | |
477 "lib-src"))) | |
478 | |
479 (defun packages-find-package-info-path (packages) | |
480 "Construct the info-path component for packages. | |
481 PACKAGES is a list of package directories." | |
482 (packages-find-package-library-path packages '("info"))) | |
483 | |
484 (defun packages-find-package-data-path (packages) | |
485 "Construct the data-path component for packages. | |
486 PACKAGES is a list of package directories." | |
487 (paths-find-recursive-load-path | |
488 (packages-find-package-library-path packages | |
489 '("etc")) | |
490 packages-data-path-depth)) | |
491 | |
492 ;; Loading package initialization files | |
493 | |
494 (defun packages-load-package-lisps (package-load-path base) | |
495 "Load all Lisp files of a certain name along a load path. | |
496 BASE is the base name of the files." | |
497 (mapcar #'(lambda (dir) | |
498 (let ((file-name (expand-file-name base dir))) | |
499 (condition-case error | |
500 (load file-name t t) | |
501 (error | |
502 (warn (format "Autoload error in: %s:\n\t%s" | |
503 file-name | |
504 (with-output-to-string | |
505 (display-error error nil)))))))) | |
506 package-load-path)) | |
507 | |
508 (defun packages-load-package-auto-autoloads (package-load-path) | |
509 "Load auto-autoload files along a load path." | |
510 (packages-load-package-lisps package-load-path | |
511 (file-name-sans-extension autoload-file-name))) | |
512 | |
513 (defun packages-handle-package-dumped-lisps (handle package-load-path) | |
514 "Load dumped-lisp.el files along a load path. | |
515 Call HANDLE on each file off definitions of PACKAGE-LISP there." | |
516 (mapcar #'(lambda (dir) | |
517 (let ((file-name (expand-file-name "dumped-lisp.el" dir))) | |
518 (if (file-exists-p file-name) | |
519 (let (package-lisp | |
520 ;; 20.4 packages could set this | |
521 preloaded-file-list) | |
522 (load file-name) | |
523 ;; dumped-lisp.el could have set this ... | |
524 (if package-lisp | |
525 (mapcar #'(lambda (base) | |
526 (funcall handle base)) | |
527 package-lisp)))))) | |
528 package-load-path)) | |
529 | |
530 (defun packages-load-package-dumped-lisps (package-load-path) | |
531 "Load dumped-lisp.el files along a load path. | |
532 Also load files off PACKAGE-LISP definitions there" | |
533 (packages-handle-package-dumped-lisps #'load package-load-path)) | |
534 | |
535 (defun packages-collect-package-dumped-lisps (package-load-path) | |
536 "Load dumped-lisp.el files along a load path. | |
537 Return list of files off PACKAGE-LISP definitions there" | |
538 (let ((*files* '())) | |
539 (packages-handle-package-dumped-lisps | |
540 #'(lambda (file) | |
541 (setq *files* (cons file *files*))) | |
542 package-load-path) | |
543 (reverse *files*))) | |
544 | |
545 (provide 'packages) | |
546 | |
547 ;;; packages.el ends here |