OVH Cloud OVH Cloud

Ediff et .cvsignore

3 réponses
Avatar
drkm
Bonsoir

Connaissez-vous le moyen de filtrer, lorsque l'on utilise `edirs'
(càd `ediff-directories'), non pas au moyen d'une regexp, mais en
fonction d'un fichier « .cvsignore » ?

Si cela n'existe pas, je ne suis pas contre écrire un peu de code.
J'ai jeté un oeil à « ediff-mult.el », qui contient un prometteur
« Generally, to implement a new multisession capability within Ediff,
you need to tell it ... », mais je suis un peu perdu. Quelqu'un
a-t-il une expérience à partager à ce sujet ? Ou une doc plus
verbeuse ?

Beaucoup de ces fonctions travaillent de plus sur des regexps. Si
seulement il y avait moyen de spécifier une liste de fichiers dont ne
pas tenir compte, je devrais pouvoir m'en sortir.

Une idée ?

--drkm

3 réponses

Avatar
drkm
drkm writes:

Connaissez-vous le moyen de filtrer, lorsque l'on utilise `edirs'
(càd `ediff-directories'), non pas au moyen d'une regexp, mais en
fonction d'un fichier « .cvsignore » ?



Le seul moyen que j'ai trouvé, c'est de modifier
`ediff-intersect-directories'. J'y ai grefé un mécanisme assez
simple, mais ÀMHA assez général, de filtres. Cfr. les patches en fin
d'article.

Il suffit alors de renseigner quelque chose comme :

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

dans son .emacs ou une commande wrappant `edirs', pour filtrer les
fichiers renseignés dans un .cvsignore ainsi que le répertoire ".~"
que crée chez moi Emacs dans chaque répertoire pour les sauvegardes :

backup-directory-alist
==> (("." . ".~/"))

J'ai également ajouté de tels filtres pour fonctionner sur des
regexps ou des patterns contenant des wildcards (comme utilisés dans
les shells). Il est de plus relativement simple d'ajouter son propre
filtre (qui peut filtrer, mais aussi ajouter des entrées).

Qu'en pensez-vous ?

--drkm

--- ediff-diff.el.old 2004-01-03 14:11:22.000000000 +0100
+++ ediff-diff.el 2004-12-30 06:49:00.000000000 +0100
@@ -1338,6 +1338,13 @@
(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 Mon Jul 26 10:42:02 2004
--- ediff-mult.el Thu Dec 30 07:22:20 2004
***************
*** 508,513 ****
--- 508,602 ----
ediff-membership-code2
ediff-membership-code3))

+ (defcustom ediff-dir-contents-filters nil
+ "List of function, used to filter directory contents for dir operations."
+ :type '(repeat function)
+ :group 'ediff)
+
+ (defun ediff-get-dirs-contents (dir1 dir2 dir3 regexp)
+ "Get contents of these directories.
+ Use REGEXP if specified to select only files matching. Use
+ `ediff-dir-contents-filters' to filter the result."
+ (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 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)
+ (setq res (funcall filter res dir1 dir2 dir3)))
+ res)))
+
+ (defcustom ediff-filter-out-names-data nil
+ "List of names to filter out. See `ediff-dir-contents-filters'."
+ :group 'ediff)
+
+ (defun ediff-filter-out-names (content dir1 dir2 dir3)
+ "Filter out names contained in `ediff-filter-out-names-data'."
+ (dolist (name ediff-filter-out-names-data)
+ (setq content (delete name content)))
+ content)
+
+ (defcustom ediff-filter-out-regexps-data nil
+ "List of regexps to filter out. See `ediff-dir-contents-filters'."
+ :group 'ediff)
+
+ (defun ediff-filter-out-regexps (content dir1 dir2 dir3)
+ "Filter out regexps contained in `ediff-filter-out-regexps-data'."
+ (dolist (name ediff-filter-out-regexps-data)
+ (setq content (delete* name content :test 'string-match)))
+ content)
+
+ (defcustom ediff-filter-out-wildcards-data nil
+ "List of wildcards to filter out. See `ediff-dir-contents-filters'."
+ :group 'ediff)
+
+ (defun ediff-filter-out-wildcards (content dir1 dir2 dir3)
+ "Filter out wildcards contained in `ediff-filter-out-wildcards-data'."
+ (mapc (lambda (match) (setq content (delete match content)))
+ (apply 'nconc (mapcar 'file-expand-wildcards
+ ediff-filter-out-wildcards-data)))
+ content)
+
+ (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 filename (car files))
+ (buffer-string))
+ "[ n]+" t))))
+
+ (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)))
+
;; 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
--- 637,646 ----
(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
Avatar
Matthieu Moy
drkm writes:

Connaissez-vous le moyen de filtrer, lorsque l'on utilise `edirs'
(càd `ediff-directories'), non pas au moyen d'une regexp, mais en
fonction d'un fichier « .cvsignore » ?



As tu pensé a une fonction a priori assez simple qui lirait un
.cvsignore et qui le convertirait en regexp ?

--
Matthieu
Avatar
drkm
Matthieu Moy writes:

drkm writes:

Connaissez-vous le moyen de filtrer, lorsque l'on utilise `edirs'
(càd `ediff-directories'), non pas au moyen d'une regexp, mais en
fonction d'un fichier « .cvsignore » ?



As tu pensé a une fonction a priori assez simple qui lirait un
.cvsignore et qui le convertirait en regexp ?



Je n'y avais pas pensé, non. As-tu vu le patch que j'ai proposé ?
Au lieu de devoir se ramener à une regexp, il permet l'utilisation de
fonction de filtrage.

Le problème, pour ce qui est de transformer le contenu d'un
.cvsignore en regexp, c'est qu'il est constitué de patterns de shell,
contenant des « wildcards ». Il existe une fonction
`wildcard-to-regxep()', mais qui transforme un seul pattern. Il faut
donc concaténer les regexps au moyen de "|", ce qui n'est pas très
efficace.

Mais peut-être existe-t-il une fonction d'optimisation de regexps
(un peu comme `opt-regexp()' pour les chaînes de caractères) ?

Je pense que je vais proposer le patch sur emacs-devel. Je garde
ton idée au cas où il serait refusé, en tant que solution
non-intrusive.

Merci.

--drkm