From a000a15c4aeaff7314f5b17207a677fcea2e2b19 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Tue, 15 Sep 2026 14:53:35 +0300 Subject: [PATCH 1/2] [Fix #2100] Stop stubbing file-exists-p in the dirconfig specs The dirconfig parser specs faked the file with an always-true `file-exists-p' spy. Under native compilation that breaks as soon as a primitive gets redefined while the spy is active: Emacs looks for the subr trampoline's .eln with `file-exists-p', is told it's there, and fails to load a file that doesn't exist. Buttercup redefines `message' when it captures the prefix-less dirconfig warning, so on a cold eln cache (a distro build, say) two of the specs died with native-lisp-load-failed. They now write a real `.projectile' into the sandbox instead. That also retires the 2023 workaround of keeping `insert-file-contents' out of trampoline compilation, which existed only for these specs. The spec that parsed the same file twice with different comment prefixes is split in two, since the parse is now cached against the file. --- test/projectile-ignore-test.el | 114 ++++++++++++++------------------ test/projectile-test-helpers.el | 5 -- 2 files changed, 49 insertions(+), 70 deletions(-) diff --git a/test/projectile-ignore-test.el b/test/projectile-ignore-test.el index 005d5fa2b..316d23383 100644 --- a/test/projectile-ignore-test.el +++ b/test/projectile-ignore-test.el @@ -232,85 +232,69 @@ (clrhash projectile--glob-keep-warned-projects) (clrhash projectile--prefixless-dirconfig-warned-projects)) (it "parses dirconfig and returns directories to ignore and keep" - (spy-on 'file-exists-p :and-return-value t) - (spy-on 'file-truename :and-call-fake (lambda (filename) filename)) - (spy-on 'insert-file-contents :and-call-fake - (lambda (filename) - (save-excursion (insert "\n-exclude\n+include\n#may-be-a-comment\nno-prefix\n left-wspace\nright-wspace\t\n")))) - (expect (projectile-parse-dirconfig-file) - :to-equal (make-projectile-dirconfig - :keep '("include/") - :ignore '("exclude" - "#may-be-a-comment" - "no-prefix" - "left-wspace" - "right-wspace") - :prefixless-ignore '("#may-be-a-comment" - "no-prefix" - "left-wspace" - "right-wspace"))) - ;; same test - but with comment lines enabled using prefix '#' - (let ((projectile-dirconfig-comment-prefix ?#)) + (projectile-test-with-project + ((".projectile" . "\n-exclude\n+include\n#may-be-a-comment\nno-prefix\n left-wspace\nright-wspace\t\n")) (expect (projectile-parse-dirconfig-file) :to-equal (make-projectile-dirconfig :keep '("include/") :ignore '("exclude" + "#may-be-a-comment" "no-prefix" "left-wspace" "right-wspace") - :prefixless-ignore '("no-prefix" + :prefixless-ignore '("#may-be-a-comment" + "no-prefix" "left-wspace" "right-wspace"))))) + (it "drops comment lines when a comment prefix is set" + (projectile-test-with-project + ((".projectile" . "\n-exclude\n+include\n#may-be-a-comment\nno-prefix\n left-wspace\nright-wspace\t\n")) + (let ((projectile-dirconfig-comment-prefix ?#)) + (expect (projectile-parse-dirconfig-file) + :to-equal (make-projectile-dirconfig + :keep '("include/") + :ignore '("exclude" + "no-prefix" + "left-wspace" + "right-wspace") + :prefixless-ignore '("no-prefix" + "left-wspace" + "right-wspace")))))) (it "skips leading whitespace before dispatching on the prefix" - (spy-on 'file-exists-p :and-return-value t) - (spy-on 'insert-file-contents :and-call-fake - (lambda (_filename) - (save-excursion - (insert " -indented-exclude\n" - "\t+indented-include\n" - " !indented-ensure\n" - " no-prefix-indented\n")))) - (expect (projectile-parse-dirconfig-file) - :to-equal (make-projectile-dirconfig - :keep '("indented-include/") - :ignore '("indented-exclude" "no-prefix-indented") - :ensure '("indented-ensure") - :prefixless-ignore '("no-prefix-indented")))) - (it "treats indented comment-prefix lines as comments" - (spy-on 'file-exists-p :and-return-value t) - (spy-on 'insert-file-contents :and-call-fake - (lambda (_filename) - (save-excursion - (insert " # indented comment\n" - "-keep-this\n")))) - (let ((projectile-dirconfig-comment-prefix ?#)) + (projectile-test-with-project + ((".projectile" . (concat " -indented-exclude\n" + "\t+indented-include\n" + " !indented-ensure\n" + " no-prefix-indented\n"))) (expect (projectile-parse-dirconfig-file) - :to-equal (make-projectile-dirconfig :ignore '("keep-this"))))) + :to-equal (make-projectile-dirconfig + :keep '("indented-include/") + :ignore '("indented-exclude" "no-prefix-indented") + :ensure '("indented-ensure") + :prefixless-ignore '("no-prefix-indented"))))) + (it "treats indented comment-prefix lines as comments" + (projectile-test-with-project + ((".projectile" . " # indented comment\n-keep-this\n")) + (let ((projectile-dirconfig-comment-prefix ?#)) + (expect (projectile-parse-dirconfig-file) + :to-equal (make-projectile-dirconfig :ignore '("keep-this")))))) (it "warns once per project even when multiple + entries contain globs" - (spy-on 'file-exists-p :and-return-value t) - (spy-on 'insert-file-contents :and-call-fake - (lambda (_filename) - (save-excursion (insert "+/*.json\n+/src\n+/[abc]/lib\n")))) - (spy-on 'display-warning) - (projectile-parse-dirconfig-file) - (projectile-parse-dirconfig-file) - (expect 'display-warning :to-have-been-called-times 1)) + (projectile-test-with-project + ((".projectile" . "+/*.json\n+/src\n+/[abc]/lib\n")) + (spy-on 'display-warning) + (projectile-parse-dirconfig-file) + (projectile-parse-dirconfig-file) + (expect 'display-warning :to-have-been-called-times 1))) (it "does not warn for plain + subdirectory entries" - (spy-on 'file-exists-p :and-return-value t) - (spy-on 'insert-file-contents :and-call-fake - (lambda (_filename) - (save-excursion (insert "+/src\n+/tests/foo\n")))) - (spy-on 'display-warning) - (projectile-parse-dirconfig-file) - (expect 'display-warning :not :to-have-been-called)) + (projectile-test-with-project ((".projectile" . "+/src\n+/tests/foo\n")) + (spy-on 'display-warning) + (projectile-parse-dirconfig-file) + (expect 'display-warning :not :to-have-been-called))) (it "does not warn for - ignore entries that contain globs" - (spy-on 'file-exists-p :and-return-value t) - (spy-on 'insert-file-contents :and-call-fake - (lambda (_filename) - (save-excursion (insert "-*.json\n-build/*.tmp\n")))) - (spy-on 'display-warning) - (projectile-parse-dirconfig-file) - (expect 'display-warning :not :to-have-been-called))) + (projectile-test-with-project ((".projectile" . "-*.json\n-build/*.tmp\n")) + (spy-on 'display-warning) + (projectile-parse-dirconfig-file) + (expect 'display-warning :not :to-have-been-called)))) (describe "projectile-parse-dirconfig-file with a real file" (before-each diff --git a/test/projectile-test-helpers.el b/test/projectile-test-helpers.el index 325e9aa01..d60efd6c1 100644 --- a/test/projectile-test-helpers.el +++ b/test/projectile-test-helpers.el @@ -27,11 +27,6 @@ ;;; Code: -;; needed for the tests to work with native compilation -(with-eval-after-load 'comp - (push 'insert-file-contents - native-comp-never-optimize-functions)) - (require 'projectile) (require 'buttercup) From db8717b79e6f49d4671b1390c33c7583ecc57a06 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Tue, 15 Sep 2026 15:39:55 +0300 Subject: [PATCH 2/2] Add CHANGELOG entry for the native-comp spec fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6816912d2..584f762bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ ### Bugs fixed +- [#2191](https://github.com/bbatsov/projectile/pull/2191): The test suite passes under native compilation with an empty eln cache, as in distro package builds, instead of failing two dirconfig specs with `native-lisp-load-failed` ([#2100](https://github.com/bbatsov/projectile/issues/2100)). - [#2190](https://github.com/bbatsov/projectile/pull/2190): Alien indexing no longer hands git exclude pathspecs to an `fd` whose `projectile-git-fd-args` lacks `--strip-cwd-prefix`, which made it fail with `No valid search paths given` ([#2187](https://github.com/bbatsov/projectile/issues/2187)). - [#2183](https://github.com/bbatsov/projectile/pull/2183): `projectile-run-test-at-point` now builds a usable file path when the project is reached through a symlink (anything under `/tmp` on macOS, or a symlinked `~/src`), instead of one that climbs out of the project and gets rejected by the test runner. - [#2178](https://github.com/bbatsov/projectile/pull/2178): The file-extension filter of `projectile-replace` and friends is now shell-quoted. ag received it unquoted, so a `*.el` filter reached it as the regexp `.el$` and also matched files ending in `model` or `panel`; on the other tools an extension containing a quote broke the command outright.