2001-07-16 12:23:00 +00:00
|
|
|
|
;;; shadow.el --- locate Emacs Lisp file shadowings
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
2014-01-01 07:43:34 +00:00
|
|
|
|
;; Copyright (C) 1995, 2001-2014 Free Software Foundation, Inc.
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
;; Author: Terry Jones <terry@santafe.edu>
|
|
|
|
|
;; Keywords: lisp
|
|
|
|
|
;; Created: 15 December 1995
|
|
|
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
|
2008-05-06 03:21:21 +00:00
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
2008-05-06 03:21:21 +00:00
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
;; 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
|
2008-05-06 03:21:21 +00:00
|
|
|
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
1996-01-14 07:34:30 +00:00
|
|
|
|
|
2010-10-08 17:44:53 -07:00
|
|
|
|
;; The functions in this file detect (`load-path-shadows-find')
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;; 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 list-load-path-shadows
|
|
|
|
|
;;
|
|
|
|
|
;; or run it non-interactively via:
|
|
|
|
|
;;
|
2009-07-22 02:34:11 +00:00
|
|
|
|
;; emacs -batch -f list-load-path-shadows
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;;
|
2013-10-12 17:31:19 -07:00
|
|
|
|
;; Thanks to Francesco Potortì <pot@cnuce.cnr.it> for suggestions,
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;; rewritings & speedups.
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
2002-11-19 15:01:56 +00:00
|
|
|
|
(defgroup lisp-shadow nil
|
1998-04-05 18:26:32 +00:00
|
|
|
|
"Locate Emacs Lisp file shadowings."
|
2010-10-07 20:05:09 -07:00
|
|
|
|
:prefix "load-path-shadows-"
|
1998-04-05 18:26:32 +00:00
|
|
|
|
:group 'lisp)
|
|
|
|
|
|
2010-10-07 20:05:09 -07:00
|
|
|
|
(define-obsolete-variable-alias 'shadows-compare-text-p
|
|
|
|
|
'load-path-shadows-compare-text "23.3")
|
|
|
|
|
|
|
|
|
|
(defcustom load-path-shadows-compare-text nil
|
2009-07-22 02:34:11 +00:00
|
|
|
|
"If non-nil, then shadowing files are reported only if their text differs.
|
1998-04-05 18:26:32 +00:00
|
|
|
|
This is slower, but filters out some innocuous shadowing."
|
|
|
|
|
:type 'boolean
|
2002-11-19 15:01:56 +00:00
|
|
|
|
:group 'lisp-shadow)
|
1997-09-25 01:33:26 +00:00
|
|
|
|
|
2010-10-08 17:44:53 -07:00
|
|
|
|
(defun load-path-shadows-find (&optional path)
|
1996-01-08 22:52:14 +00:00
|
|
|
|
"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."
|
|
|
|
|
(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.
|
2009-11-10 08:06:53 +00:00
|
|
|
|
(dolist (pp (or path load-path))
|
|
|
|
|
(setq dir (directory-file-name (file-truename (or pp "."))))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(if (member dir true-names)
|
|
|
|
|
;; We have already considered this PATH redundant directory.
|
2007-01-29 11:55:30 +00:00
|
|
|
|
;; Show the redundancy if we are interactive, unless the PATH
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;; dir is nil or "." (these redundant directories are just a
|
|
|
|
|
;; result of the current working directory, and are therefore
|
|
|
|
|
;; not always redundant).
|
|
|
|
|
(or noninteractive
|
2009-11-10 08:06:53 +00:00
|
|
|
|
(and pp
|
|
|
|
|
(not (string= pp "."))
|
|
|
|
|
(message "Ignoring redundant directory %s" pp)))
|
1997-09-25 01:33:26 +00:00
|
|
|
|
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(setq true-names (append true-names (list dir)))
|
2009-11-10 08:06:53 +00:00
|
|
|
|
(setq dir (directory-file-name (or pp ".")))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(setq curr-files (if (file-accessible-directory-p dir)
|
2005-11-19 16:53:48 +00:00
|
|
|
|
(directory-files dir nil ".\\.elc?\\(\\.gz\\)?$" t)))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(and curr-files
|
|
|
|
|
(not noninteractive)
|
1996-07-20 06:12:06 +00:00
|
|
|
|
(message "Checking %d files in %s..." (length curr-files) dir))
|
1997-09-25 01:33:26 +00:00
|
|
|
|
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(setq files-seen-this-dir nil)
|
|
|
|
|
|
2009-11-10 08:06:53 +00:00
|
|
|
|
(dolist (file curr-files)
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
2005-11-19 16:53:48 +00:00
|
|
|
|
(if (string-match "\\.gz$" file)
|
|
|
|
|
(setq file (substring file 0 -3)))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(setq file (substring
|
|
|
|
|
file 0 (if (string= (substring file -1) "c") -4 -3)))
|
|
|
|
|
|
1997-08-08 21:32:50 +00:00
|
|
|
|
;; FILE now contains the current file name, with no suffix.
|
|
|
|
|
(unless (or (member file files-seen-this-dir)
|
|
|
|
|
;; Ignore these files.
|
2014-03-05 21:01:02 -05:00
|
|
|
|
(member file (list "subdirs" "leim-list"
|
|
|
|
|
(file-name-sans-extension
|
|
|
|
|
dir-locals-file))))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;; 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))
|
2003-02-04 13:24:35 +00:00
|
|
|
|
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(if (setq orig-dir (assoc file files))
|
|
|
|
|
;; This file was seen before, we have a shadowing.
|
1997-09-25 01:33:26 +00:00
|
|
|
|
;; Report it unless the files are identical.
|
|
|
|
|
(let ((base1 (concat (cdr orig-dir) "/" file))
|
|
|
|
|
(base2 (concat dir "/" file)))
|
2010-10-07 20:05:09 -07:00
|
|
|
|
(if (not (and load-path-shadows-compare-text
|
|
|
|
|
(load-path-shadows-same-file-or-nonexistent
|
1997-09-25 01:33:26 +00:00
|
|
|
|
(concat base1 ".el") (concat base2 ".el"))
|
|
|
|
|
;; This is a bit strict, but safe.
|
2010-10-07 20:05:09 -07:00
|
|
|
|
(load-path-shadows-same-file-or-nonexistent
|
1997-09-25 01:33:26 +00:00
|
|
|
|
(concat base1 ".elc") (concat base2 ".elc"))))
|
1998-05-21 01:55:57 +00:00
|
|
|
|
(setq shadows
|
|
|
|
|
(append shadows (list base1 base2)))))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
;; Not seen before, add it to the list of seen files.
|
2009-11-10 08:06:53 +00:00
|
|
|
|
(setq files (cons (cons file dir) files)))))))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
;; Return the list of shadowings.
|
|
|
|
|
shadows))
|
|
|
|
|
|
2010-10-08 17:44:53 -07:00
|
|
|
|
(define-obsolete-function-alias 'find-emacs-lisp-shadows
|
|
|
|
|
'load-path-shadows-find "23.3")
|
|
|
|
|
|
1997-09-25 01:33:26 +00:00
|
|
|
|
;; Return true if neither file exists, or if both exist and have identical
|
|
|
|
|
;; contents.
|
2010-10-07 20:05:09 -07:00
|
|
|
|
(defun load-path-shadows-same-file-or-nonexistent (f1 f2)
|
1997-09-25 01:33:26 +00:00
|
|
|
|
(let ((exists1 (file-exists-p f1))
|
|
|
|
|
(exists2 (file-exists-p f2)))
|
|
|
|
|
(or (and (not exists1) (not exists2))
|
|
|
|
|
(and exists1 exists2
|
|
|
|
|
(or (equal (file-truename f1) (file-truename f2))
|
|
|
|
|
;; As a quick test, avoiding spawning a process, compare file
|
|
|
|
|
;; sizes.
|
|
|
|
|
(and (= (nth 7 (file-attributes f1))
|
|
|
|
|
(nth 7 (file-attributes f2)))
|
2004-01-03 12:12:01 +00:00
|
|
|
|
(eq 0 (call-process "cmp" nil nil nil "-s" f1 f2))))))))
|
2010-10-06 19:37:39 -07:00
|
|
|
|
|
2010-10-07 10:22:51 -07:00
|
|
|
|
(defvar load-path-shadows-font-lock-keywords
|
2012-09-11 00:13:21 -07:00
|
|
|
|
;; The idea is that shadows of files supplied with Emacs are more
|
|
|
|
|
;; serious than various versions of external packages shadowing each
|
|
|
|
|
;; other.
|
2010-10-06 19:37:39 -07:00
|
|
|
|
`((,(format "hides \\(%s.*\\)"
|
2012-09-11 00:13:21 -07:00
|
|
|
|
(file-name-directory
|
|
|
|
|
(or (locate-library "simple")
|
|
|
|
|
(file-name-as-directory
|
|
|
|
|
(expand-file-name "../lisp" data-directory)))))
|
2010-10-06 19:37:39 -07:00
|
|
|
|
. (1 font-lock-warning-face)))
|
2010-10-07 10:17:18 -07:00
|
|
|
|
"Keywords to highlight in `load-path-shadows-mode'.")
|
2010-10-06 19:37:39 -07:00
|
|
|
|
|
2010-10-07 10:17:18 -07:00
|
|
|
|
(define-derived-mode load-path-shadows-mode fundamental-mode "LP-Shadows"
|
2010-10-06 19:37:39 -07:00
|
|
|
|
"Major mode for load-path shadows buffer."
|
|
|
|
|
(set (make-local-variable 'font-lock-defaults)
|
2010-10-07 10:22:51 -07:00
|
|
|
|
'((load-path-shadows-font-lock-keywords)))
|
2010-10-06 19:37:39 -07:00
|
|
|
|
(setq buffer-undo-list t
|
|
|
|
|
buffer-read-only t))
|
|
|
|
|
|
|
|
|
|
;; TODO use text-properties instead, a la dired.
|
|
|
|
|
(require 'button)
|
2010-10-07 10:22:51 -07:00
|
|
|
|
(define-button-type 'load-path-shadows-find-file
|
2010-10-06 19:37:39 -07:00
|
|
|
|
'follow-link t
|
|
|
|
|
;; 'face 'default
|
|
|
|
|
'action (lambda (button)
|
|
|
|
|
(let ((file (concat (button-get button 'shadow-file) ".el")))
|
|
|
|
|
(or (file-exists-p file)
|
|
|
|
|
(setq file (concat file ".gz")))
|
|
|
|
|
(if (file-readable-p file)
|
|
|
|
|
(pop-to-buffer (find-file-noselect file))
|
|
|
|
|
(error "Cannot read file"))))
|
|
|
|
|
'help-echo "mouse-2, RET: find this file")
|
|
|
|
|
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
;;;###autoload
|
2009-07-22 02:34:11 +00:00
|
|
|
|
(defun list-load-path-shadows (&optional stringp)
|
1996-07-23 13:56:33 +00:00
|
|
|
|
"Display a list of Emacs Lisp files that shadow other files.
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
2009-07-22 02:34:11 +00:00
|
|
|
|
If STRINGP is non-nil, returns any shadows as a string.
|
|
|
|
|
Otherwise, if interactive shows any shadows in a `*Shadows*' buffer;
|
|
|
|
|
else prints messages listing any shadows.
|
|
|
|
|
|
2007-01-29 11:55:30 +00:00
|
|
|
|
This function lists potential load path problems. Directories in
|
|
|
|
|
the `load-path' variable are searched, in order, for Emacs Lisp
|
1996-07-23 13:56:33 +00:00
|
|
|
|
files. When a previously encountered file name is found again, a
|
|
|
|
|
message is displayed indicating that the later file is \"hidden\" by
|
1996-01-08 22:52:14 +00:00
|
|
|
|
the earlier.
|
|
|
|
|
|
|
|
|
|
For example, suppose `load-path' is set to
|
|
|
|
|
|
2013-04-26 00:25:45 -07:00
|
|
|
|
\(\"/usr/share/emacs/site-lisp\" \"/usr/share/emacs/24.3/lisp\")
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
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:
|
2013-04-26 00:25:45 -07:00
|
|
|
|
\(require 'XXX), (autoload .... \"XXX\"), (load-library \"XXX\") etc.
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
2013-04-26 00:25:45 -07:00
|
|
|
|
The first XXX.el file prevents Emacs from seeing the second (unless
|
|
|
|
|
the second is loaded explicitly via `load-file').
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
When not intended, such shadowings can be the source of subtle
|
|
|
|
|
problems. For example, the above situation may have arisen because the
|
2006-11-06 02:35:42 +00:00
|
|
|
|
XXX package was not distributed with versions of Emacs prior to
|
2013-04-26 00:25:45 -07:00
|
|
|
|
24.3. A system administrator downloaded XXX from elsewhere and installed
|
2006-11-06 02:35:42 +00:00
|
|
|
|
it. Later, XXX was updated and included in the Emacs distribution.
|
2013-04-26 00:25:45 -07:00
|
|
|
|
Unless the system administrator checks for this, the new version of XXX
|
|
|
|
|
will be hidden behind the old (which may no longer work with the new
|
|
|
|
|
Emacs version).
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
This function performs these checks and flags all possible
|
|
|
|
|
shadowings. Because a .el file may exist without a corresponding .elc
|
2013-04-26 00:25:45 -07:00
|
|
|
|
\(or vice-versa), these suffixes are essentially ignored. A file
|
|
|
|
|
XXX.elc in an early directory (that does not contain XXX.el) is
|
1996-01-08 22:52:14 +00:00
|
|
|
|
considered to shadow a later file XXX.el, and vice-versa.
|
|
|
|
|
|
2009-07-22 02:34:11 +00:00
|
|
|
|
Shadowings are located by calling the (non-interactive) companion
|
2010-10-08 17:44:53 -07:00
|
|
|
|
function, `load-path-shadows-find'."
|
1996-01-08 22:52:14 +00:00
|
|
|
|
(interactive)
|
2013-04-26 00:25:45 -07:00
|
|
|
|
(let* ((shadows (load-path-shadows-find load-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"))))
|
|
|
|
|
(with-temp-buffer
|
|
|
|
|
(while shadows
|
|
|
|
|
(insert (format "%s hides %s\n" (car shadows)
|
|
|
|
|
(car (cdr shadows))))
|
|
|
|
|
(setq shadows (cdr (cdr shadows))))
|
|
|
|
|
(if stringp
|
|
|
|
|
(buffer-string)
|
|
|
|
|
(if (called-interactively-p 'interactive)
|
|
|
|
|
;; We are interactive.
|
|
|
|
|
;; Create the *Shadows* buffer and display shadowings there.
|
|
|
|
|
(let ((string (buffer-string)))
|
|
|
|
|
(with-current-buffer (get-buffer-create "*Shadows*")
|
|
|
|
|
(display-buffer (current-buffer))
|
|
|
|
|
(load-path-shadows-mode) ; run after-change-major-mode-hook
|
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer)
|
|
|
|
|
(insert string)
|
|
|
|
|
(insert msg "\n")
|
|
|
|
|
(while (re-search-backward "\\(^.*\\) hides \\(.*$\\)"
|
|
|
|
|
nil t)
|
|
|
|
|
(dotimes (i 2)
|
|
|
|
|
(make-button (match-beginning (1+ i))
|
|
|
|
|
(match-end (1+ i))
|
|
|
|
|
'type 'load-path-shadows-find-file
|
|
|
|
|
'shadow-file
|
|
|
|
|
(match-string (1+ i)))))
|
|
|
|
|
(goto-char (point-max)))))
|
|
|
|
|
;; We are non-interactive, print shadows via message.
|
|
|
|
|
(unless (zerop n)
|
|
|
|
|
(message "This site has duplicate Lisp libraries with the same name.
|
1997-08-08 21:32:50 +00:00
|
|
|
|
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
|
1998-05-04 01:22:17 +00:00
|
|
|
|
version unless you know what you are doing.\n")
|
2013-04-26 00:25:45 -07:00
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
;; Mimic the previous behavior of using lots of messages.
|
|
|
|
|
;; I think one single message would look better...
|
|
|
|
|
(while (not (eobp))
|
|
|
|
|
(message "%s" (buffer-substring (line-beginning-position)
|
|
|
|
|
(line-end-position)))
|
|
|
|
|
(forward-line 1))
|
|
|
|
|
(message "%s" msg)))))))
|
1996-01-08 22:52:14 +00:00
|
|
|
|
|
|
|
|
|
(provide 'shadow)
|
|
|
|
|
|
|
|
|
|
;;; shadow.el ends here
|
2013-10-12 17:31:19 -07:00
|
|
|
|
|
|
|
|
|
;; Local Variables:
|
|
|
|
|
;; coding: utf-8
|
|
|
|
|
;; End:
|