[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Filtering files with Ediff

From: drkm
Subject: Filtering files with Ediff
Date: Wed, 05 Jan 2005 00:11:17 +0100
User-agent: Gnus/5.110003 (No Gnus v0.3) Emacs/21.3.50 (windows-nt)


  I looked for a way to filter out some files from those `edirs'
uses.  Basically, I want to filter out files contained in my
.cvsignore files, when applicable.  .cvsignore files contain shell
file patterns (filenames with wildcards).

  The functions used by `edirs' take a regexp to select files to be
diff-ed.  But wildcards interact not well with regexp, as far as I
know.  I know `wildcard-to-regexp', but it takes a single pattern.  So
I have to construct the complete regexp by concatenate all regexps,
separating them by "\\|".  It's not very efficient.

  Furthemore, I think a more powerfull filtering functionality could
be intresting when diff-ing directories.  So I modify
`ediff-intersect-directories' to filter out the directories contents
(the files in these directories) in function of user-provided filters.

  I also added some usefull filters (filtering strings, regexps,
wildcards and in function of .cvsignore files).  So I have this in my
.emacs to filter out ".~" and from .cvsignore files:

    ;; I have (setq backup-directory-alist '(("." . ".~"))) somewhere.

    (setq ediff-filter-out-names-data '(".~")
          ediff-dir-contents-filters  '(ediff-filter-out-names

  Does this seem to be usefull ?


*** ediff-diff.el.old   Thu Dec 23 07:01:56 2004
--- ediff-diff.el       Thu Dec 30 08:24:14 2004
*** 1338,1343 ****
--- 1338,1350 ----
                (append ediff-cmp-options (list f1 f2)))))
      (and (numberp res) (eq res 0))))
+ (defun ediff-same-file-contents-3 (f1 f2 &optional f3)
+   "Return t if F1, F2 and F3 (if applicable) have identical contents."
+   (and (ediff-same-file-contents file1 file2)
+        (or (null file3)
+            (and (ediff-same-file-contents file1 file3)
+                 (ediff-same-file-contents file2 file3)))))
  ;;; Local Variables:
  ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)

*** ediff-mult.el.old   Thu Dec 23 07:01:56 2004
--- ediff-mult.el       Tue Jan  4 23:44:10 2005
*** 508,513 ****
--- 508,620 ----
+ (defcustom ediff-dir-contents-filters nil
+   "List of function, used to filter directory contents for dir operations.
+ These functions are called with 3 or 4 arguments.  The first,
+ CONTENT, is the list to filter (a list of filenames).  The
+ remaining arguments, DIR1, DIR2 and DIR3 (optional), are the
+ directories whose are extracted CONTENT.
+ CONTENT contains only the files that are commons to these 2 (or
+ 3) directories.  The result of the call is used as the new
+ contents list.  Functions are called from the head to the tail of
+ the list."
+   :type  '(repeat function)
+   :group 'ediff)
+ (defcustom ediff-filter-out-names-data nil
+   "List of names to filter out.  See `ediff-dir-contents-filters'."
+   :type  '(repeat string)
+   :group 'ediff)
+ (defun ediff-filter-out-names (content &optional dir1 dir2 dir3)
+   "Filter out names contained in `ediff-filter-out-names-data'."
+   (dolist (name ediff-filter-out-names-data content)
+     (setq content (delete name content))))
+ (defcustom ediff-filter-out-regexps-data nil
+   "List of regexps to filter out.  See `ediff-dir-contents-filters'."
+   :type  '(repeat regexp)
+   :group 'ediff)
+ (defun ediff-filter-out-regexps (content &optional dir1 dir2 dir3)
+   "Filter out regexps contained in `ediff-filter-out-regexps-data'."
+   (dolist (regexp ediff-filter-out-regexps-data content)
+     ;; Not use CL here.
+     ;; (setq content (delete* regexp content :test 'string-match))))
+     (setq content (let* ((res '(dummy))
+                          (i   res))
+                     (dolist (c content (cdr res))
+                       (unless (string-match regexp c)
+                         (setcdr i (cons c nil))
+                         (setq i (cdr i))))))))
+ (defcustom ediff-filter-out-wildcards-data nil
+   "List of wildcards to filter out.  See `ediff-dir-contents-filters'."
+   :type  '(repeat string)
+   :group 'ediff)
+ (defun ediff-filter-out-wildcards (content &optional dir1 dir2 dir3)
+   "Filter out wildcards contained in `ediff-filter-out-wildcards-data'."
+   (let ((matches (apply 'nconc (mapcar 'file-expand-wildcards
+                                        ediff-filter-out-wildcards-data))))
+     (dolist (match matches content)
+       (setq content (delete match content)))))
+ (defun ediff-filter-out-cvsignore (content dir1 dir2 &optional dir3)
+   "Filter out patterns found in a .cvsignore file."
+   (let ((ediff-filter-out-wildcards-data (ediff-get-cvsignore-wildcards
+                                           dir1 dir2 dir3)))
+     (ediff-filter-out-wildcards content dir1 dir2 dir3)))
+ (defun ediff-get-cvsignore-wildcards (dir1 dir2 &optional dir3)
+   "Get wildcards contained in a .cvsignore file.
+ Return a list of strings.  Each element is a pattern from the
+ .cvsignore file.
+ The .cvsignore file is search in DIR1, DIR2 and DIR3 (if
+ applicable).  IF none is found, return nil.  If multiple file are
+ found, they must be exactly identicals."
+   (let ((files (delq nil (mapcar (lambda (dir)
+                                    (let ((file (concat dir ".cvsignore")))
+                                      (when (file-exists-p file)
+                                        file)))
+                                  (if (stringp dir3)
+                                      (list dir1 dir2 dir3)
+                                    (list dir1 dir2))))))
+     (when (and (> (length files) 1)
+                (not (apply 'ediff-same-file-content-3 files)))
+       (error ".cvsignore files are differents! %S" files))
+     (when files
+       (split-string (with-temp-buffer
+                       (insert-file-contents (car files))
+                       (buffer-string))
+                     "[ \n]+" t))))
+ (defun ediff-get-dirs-contents (dir1 dir2 &optional dir3 regexp)
+   "Get contents of these directories.
+ Mainly a utility routine for `ediff-intersect-directories'.  Use
+ REGEXP if specified to select only files matching.  Use
+ `ediff-dir-contents-filters' to filter the result furthemore."
+   (setq dir1 (file-name-as-directory dir1)
+         dir2 (file-name-as-directory dir2)
+         dir3 (and (stringp dir3) (file-name-as-directory dir3)))
+   (if (stringp dir3)
+       (list (cons dir1 (ediff-get-dirs-contents-1 dir1 dir2 dir3 regexp))
+             (cons dir2 (ediff-get-dirs-contents-1 dir2 dir1 dir3 regexp))
+             (cons dir3 (ediff-get-dirs-contents-1 dir3 dir1 dir2 regexp)))
+     (list (cons dir1 (ediff-get-dirs-contents-1 dir1 dir2 dir3 regexp))
+           (cons dir2 (ediff-get-dirs-contents-1 dir2 dir1 dir3 regexp)))))
+ (defun ediff-get-dirs-contents-1 (dir1 dir2 &optional dir3 regexp)
+   (mapcar (lambda (f)
+             (ediff-add-slash-if-directory dir1 f))
+           (let* ((default-directory (expand-file-name dir1))
+                  (res               (directory-files dir1 nil regexp)))
+             (setq res (delete "." (delete ".." res)))
+             (dolist (filter ediff-dir-contents-filters res)
+               (setq res (funcall filter res dir1 dir2 dir3))))))
  ;; DIR1, DIR2, DIR3 are directories.  DIR3 can be nil.
  ;; OUTPUT-DIR is a directory for auto-storing the results of merge jobs.
  ;;          Can be nil.
*** 548,573 ****
    (setq comparison-func (or comparison-func 'string=))
    (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 common-part difflist)
!     (setq auxdir1     (file-name-as-directory dir1)
!         lis1          (directory-files auxdir1 nil regexp)
!         lis1          (delete "."  lis1)
!         lis1          (delete ".." lis1)
!         lis1          (mapcar
!                        (lambda (elt)
!                          (ediff-add-slash-if-directory auxdir1 elt))
!                        lis1)
!         auxdir2       (file-name-as-directory dir2)
!         lis2          (mapcar
!                        (lambda (elt)
!                          (ediff-add-slash-if-directory auxdir2 elt))
!                        (directory-files auxdir2 nil regexp)))
!     (if (stringp dir3)
!       (setq auxdir3   (file-name-as-directory dir3)
!             lis3      (mapcar
!                        (lambda (elt)
!                          (ediff-add-slash-if-directory auxdir3 elt))
!                        (directory-files auxdir3 nil regexp))))
      (if (ediff-nonempty-string-p merge-autostore-dir)
        (setq merge-autostore-dir
--- 655,664 ----
    (setq comparison-func (or comparison-func 'string=))
    (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 common-part difflist)
!     (let ((res (ediff-get-dirs-contents dir1 dir2 dir3 regexp)))
!       (setq auxdir1 (car (nth 0 res))  lis1 (cdr (nth 0 res))
!             auxdir2 (car (nth 1 res))  lis2 (cdr (nth 1 res))
!             auxdir3 (car (nth 2 res))  lis3 (cdr (nth 2 res))))
      (if (ediff-nonempty-string-p merge-autostore-dir)
        (setq merge-autostore-dir

reply via email to

[Prev in Thread] Current Thread [Next in Thread]