view lisp/emacs-lisp/shadow.el @ 19860:c17fd465ea95 libc-970911 libc-970912 libc-970913 libc-970914 libc-970915 libc-970916 libc-970917 libc-970918 libc-970919 libc-970920 libc-970921 libc-970922 libc-970923 libc-970924 libc-970925 libc-970926 libc-970927 libc-970928 libc-970929 libc-970930 libc-971001 libc-971018 libc-971019 libc-971020 libc-971021 libc-971022 libc-971023 libc-971024 libc-971025 libc-971026 libc-971027 libc-971028 libc-971029 libc-971030 libc-971031 libc-971101 libc-971102 libc-971103 libc-971104 libc-971105 libc-971106 libc-971107 libc-971108 libc-971109 libc-971110 libc-971111 libc-971112 libc-971113 libc-971114 libc-971115 libc-971116 libc-971117 libc-971118 libc-971120 libc-971121 libc-971122 libc-971123 libc-971124 libc-971125 libc-971126 libc-971127 libc-971128 libc-971129 libc-971130 libc-971201 libc-971203 libc-971204 libc-971205 libc-971206 libc-971207 libc-971208 libc-971209 libc-971210 libc-971211 libc-971212 libc-971213 libc-971214 libc-971217 libc-971218 libc-971219 libc-971220 libc-971221 libc-971222 libc-971223 libc-971224 libc-971225 libc-971226 libc-971227 libc-971228 libc-971229 libc-971230 libc-971231 libc-980103 libc-980104 libc-980105 libc-980106 libc-980107 libc-980108 libc-980109 libc-980110 libc-980111 libc-980112 libc-980114 libc-980115 libc-980116 libc-980117 libc-980118 libc-980119 libc-980120 libc-980121 libc-980122 libc-980123 libc-980124 libc-980125 libc-980126 libc-980127 libc-980128

typos.
author Jeff Law <law@redhat.com>
date Wed, 10 Sep 1997 21:16:20 +0000
parents 04175c55c49b
children 199256234202
line wrap: on
line source

;;; shadow.el --- Locate Emacs Lisp file shadowings.

;; Copyright (C) 1995 Free Software Foundation, Inc.

;; Author: Terry Jones <terry@santafe.edu>
;; Keywords: lisp
;; Created: 15 December 1995

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; The functions in this file detect (`find-emacs-lisp-shadows')
;; and display (`list-load-path-shadows') potential load-path
;; problems that arise when Emacs Lisp files "shadow" each other.
;;
;; For example, a file XXX.el early in one's load-path will shadow
;; a file with the same name in a later load-path directory.  When
;; this is unintentional, it may result in problems that could have
;; been easily avoided.  This occurs often (to me) when installing a
;; new version of emacs and something in the site-lisp directory
;; has been updated and added to the emacs distribution.  The old
;; version, now outdated, shadows the new one. This is obviously
;; undesirable.
;;
;; The `list-load-path-shadows' function was run when you installed
;; this version of emacs. To run it by hand in emacs:
;;
;;     M-x load-library RET shadow RET
;;     M-x list-load-path-shadows
;;
;; or run it non-interactively via:
;;
;;     emacs -batch -l shadow.el -f list-load-path-shadows
;;
;; Thanks to Francesco Potorti` <pot@cnuce.cnr.it> for suggestions,
;; rewritings & speedups.

;;; Code:

(defun find-emacs-lisp-shadows (&optional path)
  "Return a list of Emacs Lisp files that create shadows.
This function does the work for `list-load-path-shadows'.

We traverse PATH looking for shadows, and return a \(possibly empty\)
even-length list of files.  A file in this list at position 2i shadows
the file in position 2i+1.  Emacs Lisp file suffixes \(.el and .elc\)
are stripped from the file names in the list.

See the documentation for `list-load-path-shadows' for further information."
  
  (or path (setq path load-path))

  (let (true-names			; List of dirs considered.
	shadows				; List of shadowings, to be returned.
	files				; File names ever seen, with dirs.
	dir				; The dir being currently scanned.
	curr-files			; This dir's Emacs Lisp files.
	orig-dir			; Where the file was first seen.
	files-seen-this-dir		; Files seen so far in this dir.
	file)				; The current file.

  
    (while path

      (setq dir (file-truename (or (car path) ".")))
      (if (member dir true-names)
	  ;; We have already considered this PATH redundant directory.
	  ;; Show the redundancy if we are interactiver, unless the PATH
	  ;; dir is nil or "." (these redundant directories are just a
	  ;; result of the current working directory, and are therefore
	  ;; not always redundant).
	  (or noninteractive
	      (and (car path)
		   (not (string= (car path) "."))
		   (message "Ignoring redundant directory %s" (car path))))
	
	(setq true-names (append true-names (list dir)))
	(setq dir (or (car path) "."))
	(setq curr-files (if (file-accessible-directory-p dir)
                               (directory-files dir nil ".\\.elc?$" t)))
	(and curr-files
	     (not noninteractive)
	     (message "Checking %d files in %s..." (length curr-files) dir))
	
	(setq files-seen-this-dir nil)

	(while curr-files

	  (setq file (car curr-files))
	  (setq file (substring
		      file 0 (if (string= (substring file -1) "c") -4 -3)))

	  ;; FILE now contains the current file name, with no suffix.
	  (unless (or (member file files-seen-this-dir)
		      ;; Ignore these files.
		      (member file '("subdirs")))
	    ;; File has not been seen yet in this directory.
	    ;; This test prevents us declaring that XXX.el shadows
	    ;; XXX.elc (or vice-versa) when they are in the same directory.
	    (setq files-seen-this-dir (cons file files-seen-this-dir))
	      
	    (if (setq orig-dir (assoc file files))
		;; This file was seen before, we have a shadowing.
		(setq shadows
		      (append shadows
			      (list (concat (cdr orig-dir) "/" file)
				    (concat dir "/" file))))

	      ;; Not seen before, add it to the list of seen files.
	      (setq files (cons (cons file dir) files))))

	  (setq curr-files (cdr curr-files))))
	(setq path (cdr path)))

    ;; Return the list of shadowings.
    shadows))


;;;###autoload
(defun list-load-path-shadows ()
  "Display a list of Emacs Lisp files that shadow other files.

This function lists potential load-path problems.  Directories in the
`load-path' variable are searched, in order, for Emacs Lisp
files.  When a previously encountered file name is found again, a
message is displayed indicating that the later file is \"hidden\" by
the earlier.

For example, suppose `load-path' is set to

\(\"/usr/gnu/emacs/site-lisp\" \"/usr/gnu/emacs/share/emacs/19.30/lisp\"\)

and that each of these directories contains a file called XXX.el.  Then
XXX.el in the site-lisp directory is referred to by all of:
\(require 'XXX\), \(autoload .... \"XXX\"\), \(load-library \"XXX\"\) etc.

The first XXX.el file prevents emacs from seeing the second \(unless
the second is loaded explicitly via load-file\).

When not intended, such shadowings can be the source of subtle
problems.  For example, the above situation may have arisen because the
XXX package was not distributed with versions of emacs prior to
19.30.  An emacs maintainer downloaded XXX from elsewhere and installed
it.  Later, XXX was updated and included in the emacs distribution.
Unless the emacs maintainer checks for this, the new version of XXX
will be hidden behind the old \(which may no longer work with the new
emacs version\).

This function performs these checks and flags all possible
shadowings.  Because a .el file may exist without a corresponding .elc
\(or vice-versa\), these suffixes are essentially ignored.  A file
XXX.elc in an early directory \(that does not contain XXX.el\) is
considered to shadow a later file XXX.el, and vice-versa.

When run interactively, the shadowings \(if any\) are displayed in a
buffer called `*Shadows*'.  Shadowings are located by calling the
\(non-interactive\) companion function, `find-emacs-lisp-shadows'."
  
  (interactive)
  (let* ((path (copy-sequence load-path))
	(tem path)
	toplevs)
    ;; If we can find simple.el in two places,
    (while tem
      (if (file-exists-p (expand-file-name "simple.el" (car tem)))
	  (setq toplevs (cons (car tem) toplevs)))
      (setq tem (cdr tem)))
    (if (> (length toplevs) 1)
	;; Cut off our copy of load-path right before
	;; the second directory which has simple.el in it.
	;; This avoids loads of duplications between the source dir
	;; and the dir where these files were copied by installation.
	(let ((break (nth (- (length toplevs) 2) toplevs)))
	  (setq tem path)
	  (while tem
	    (if (eq (nth 1 tem) break)
		(progn
		  (setcdr tem nil)
		  (setq tem nil)))
	    (setq tem (cdr tem)))))

    (let* ((shadows (find-emacs-lisp-shadows path))
	   (n (/ (length shadows) 2))
	   (msg (format "%s Emacs Lisp load-path shadowing%s found"
			(if (zerop n) "No" (concat "\n" (number-to-string n)))
			(if (= n 1) " was" "s were"))))
      (if (interactive-p)
	  (save-excursion
	    ;; We are interactive.
	    ;; Create the *Shadows* buffer and display shadowings there.
	    (let ((output-buffer (get-buffer-create "*Shadows*")))
	      (display-buffer output-buffer)
	      (set-buffer output-buffer)
	      (erase-buffer)
	      (while shadows
		(insert (format "%s hides %s\n" (car shadows)
				(car (cdr shadows))))
		(setq shadows (cdr (cdr shadows))))
	      (insert msg "\n")))
	;; We are non-interactive, print shadows via message.
	(when shadows
	  (message "This site has duplicate Lisp libraries with the same name.
If a locally-installed Lisp library overrides a library in the Emacs release,
that can cause trouble, and you should probably remove the locally-installed
version unless you know what you are doing.\n"))
	(while shadows
	  (message "%s hides %s" (car shadows) (car (cdr shadows)))
	  (setq shadows (cdr (cdr shadows))))
	(message "%s" msg)))))

(provide 'shadow)

;;; shadow.el ends here