From 71f8b55f46af307759fb30dcf3f784092dd8834d Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Mon, 6 Sep 2021 05:01:07 +0300 Subject: [PATCH] project--files-in-directory: Fix handling of ignores * lisp/progmodes/project.el (project--files-in-directory): Pass "." as the DIR argument to 'find' because otherwise the ignore expression can match the project root directory name, which we don't want to happen (bug#50240). Fixup the resulting file names at the end with concatenation. Originally I thought it could lead to worse performance, but the results show equal or slightly better timings. * lisp/progmodes/xref.el (xref-matches-in-directory): Apply a similar fix. (xref--find-ignores-arguments): Use file-name-as-directory, so that when passed "." replace-match still had the expected effect. * test/lisp/progmodes/project-tests.el (project-ignores-bug-50240): New test. * test/lisp/progmodes/xref-tests.el (xref-matches-in-directory-filters-with-ignores): New test. --- lisp/progmodes/project.el | 12 ++++++------ lisp/progmodes/xref.el | 17 +++++++++++------ test/lisp/progmodes/project-tests.el | 15 +++++++++++++++ test/lisp/progmodes/xref-tests.el | 8 ++++++++ 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index e420a4ccca7..b6eea7e27e4 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -302,11 +302,10 @@ to find the list of ignores for each directory." ;; expanded and not left for the shell command ;; to interpret. (localdir (file-name-unquote (file-local-name (expand-file-name dir)))) - (command (format "%s -H %s %s -type f %s -print0" + (dfn (directory-file-name localdir)) + (command (format "%s -H . %s -type f %s -print0" find-program - (shell-quote-argument - (directory-file-name localdir)) ; Bug#48471 - (xref--find-ignores-arguments ignores localdir) + (xref--find-ignores-arguments ignores "./") (if files (concat (shell-quote-argument "(") " " find-name-arg " " @@ -324,8 +323,9 @@ to find the list of ignores for each directory." (unless (zerop status) (error "File listing failed: %s" (buffer-string)))))))) (project--remote-file-names - (sort (split-string output "\0" t) - #'string<)))) + (mapcar (lambda (s) (concat dfn (substring s 1))) + (sort (split-string output "\0" t) + #'string<))))) (defun project--remote-file-names (local-files) "Return LOCAL-FILES as if they were on the system of `default-directory'. diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index e594624573b..ec8b05d2943 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -1553,18 +1553,18 @@ IGNORES is a list of glob patterns for files to ignore." ;; do that reliably enough, without creating false negatives? (command (xref--rgrep-command (xref--regexp-to-extended regexp) files - (directory-file-name - (file-name-unquote - (file-local-name (expand-file-name dir)))) + "." ignores)) - (def default-directory) + (local-dir (directory-file-name + (file-name-unquote + (file-local-name (expand-file-name dir))))) (buf (get-buffer-create " *xref-grep*")) (`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist)) (status nil) (hits nil)) (with-current-buffer buf (erase-buffer) - (setq default-directory def) + (setq default-directory dir) (setq status (process-file-shell-command command nil t)) (goto-char (point-min)) @@ -1577,7 +1577,7 @@ IGNORES is a list of glob patterns for files to ignore." (user-error "Search failed with status %d: %s" status (buffer-string))) (while (re-search-forward grep-re nil t) (push (list (string-to-number (match-string line-group)) - (match-string file-group) + (concat local-dir (substring (match-string file-group) 1)) (buffer-substring-no-properties (point) (line-end-position))) hits))) (xref--convert-hits (nreverse hits) regexp))) @@ -1746,6 +1746,11 @@ directory, used as the root of the ignore globs." (cl-assert (not (string-match-p "\\`~" dir))) (if (not ignores) "" + ;; TODO: All in-tree callers are passing in just "." or "./". + ;; We can simplify. + ;; And, if we ever end up deleting xref-matches-in-directory, move + ;; this function to the project package. + (setq dir (file-name-as-directory dir)) (concat (shell-quote-argument "(") " -path " diff --git a/test/lisp/progmodes/project-tests.el b/test/lisp/progmodes/project-tests.el index 68460a9fa5b..1e3f258ac2a 100644 --- a/test/lisp/progmodes/project-tests.el +++ b/test/lisp/progmodes/project-tests.el @@ -107,4 +107,19 @@ directory name (Bug#48471)." collect (file-relative-name file dir)))) (should (equal relative-files '("some-file")))))) +(ert-deftest project-ignores-bug-50240 () + "Check that `project-files' does not ignore all files. +When `project-ignores' includes a name matching project dir." + (skip-unless (executable-find find-program)) + (project-tests--with-temporary-directory dir + (make-empty-file (expand-file-name "some-file" dir)) + (let* ((project (make-project-tests--trivial + :root (file-name-as-directory dir) + :ignores (list (file-name-nondirectory + (directory-file-name dir))))) + (files (project-files project))) + (should (equal files + (list + (expand-file-name "some-file" dir))))))) + ;;; project-tests.el ends here diff --git a/test/lisp/progmodes/xref-tests.el b/test/lisp/progmodes/xref-tests.el index d29452243b2..ff4b647ae0f 100644 --- a/test/lisp/progmodes/xref-tests.el +++ b/test/lisp/progmodes/xref-tests.el @@ -52,6 +52,14 @@ (should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 0 locs)))) (should (string-match-p "file2\\.txt\\'" (xref-location-group (nth 1 locs)))))) +(ert-deftest xref-matches-in-directory-filters-with-ignores () + (let ((locs (xref-matches-in-directory "bar" "*" xref-tests--data-dir + '("./file1.*")))) + (should (= 1 (length locs))) + (should (string-match-p "file2\\.txt\\'" (xref-location-group + (xref-item-location + (nth 0 locs))))))) + (ert-deftest xref-matches-in-directory-finds-two-matches-on-the-same-line () (let ((locs (xref-tests--locations-in-data-dir "foo"))) (should (= 2 (length locs))) -- 2.39.2