projectile
projectile copied to clipboard
Projectile fails to find project-level marker file when path not readable until root
Context: this happening eg. on TermUX, but I confirmed it on a Linux system when the project is in a directory that is only executable.
Expected behavior
Pressing 's-p f' (projectile-find-file) will fail to resolve files.
Actual behavior
Should be the same behavior as when there is no file until root, or some fallback when no project file is found.
Steps to reproduce the problem
Create a dir, eg. /home/$USER/TEMP/hidden/my_projects/
create a file in there, eg. /home/$USER/TEMP/hidden/my_projects/config.sh
then
chmod 111 /home/$USER/TEMP/hidden
so that one can go into the dir, but locked cannot be listed.
Then try to use projectil-find-file in that dir. It should fail like this:
Debugger entered--Lisp error: (file-error "Opening directory" "Permission denied" "/home/fleury/TEMP/hidden")
directory-files("/home/fleury/TEMP/hidden/" nil "\\`[^\0][^\0]*\\.sln\\'")
file-expand-wildcards("/home/fleury/TEMP/hidden/?*.sln")
projectile-expand-file-name-wildcard("?*.sln" "~/TEMP/hidden/")
#f(compiled-function (f) #<bytecode -0x35b48e202190b>)("?*.sln")
cl--position(nil ("dune-project" "pubspec.yaml" "info.rkt" "Cargo.toml" "stack.yaml" "DESCRIPTION" "Eldev" "Cask" "shard.yml" "Gemfile" ".bloop" "deps.edn" "build.boot" "project.clj" "build.sc" "build.sbt" "application.yml" "gradlew" "build.gradle" "pom.xml" "poetry.lock" "Pipfile" "tox.ini" "setup.py" "requirements.txt" "manage.py" "angular.json" "package.json" "gulpfile.js" "Gruntfile.js" "mix.exs" "rebar.config" "composer.json" "Taskfile.yml" "CMakeLists.txt" "GNUMakefile" "Makefile" "debian/control" "WORKSPACE" "flake.nix" "default.nix" "meson.build" "SConstruct" "?*.sln" "?*.fsproj" "?*.csproj" "GTAGS" "TAGS" "configure.ac" "configure.in" ...) 0 nil nil)
cl-position(nil ("dune-project" "pubspec.yaml" "info.rkt" "Cargo.toml" "stack.yaml" "DESCRIPTION" "Eldev" "Cask" "shard.yml" "Gemfile" ".bloop" "deps.edn" "build.boot" "project.clj" "build.sc" "build.sbt" "application.yml" "gradlew" "build.gradle" "pom.xml" "poetry.lock" "Pipfile" "tox.ini" "setup.py" "requirements.txt" "manage.py" "angular.json" "package.json" "gulpfile.js" "Gruntfile.js" "mix.exs" "rebar.config" "composer.json" "Taskfile.yml" "CMakeLists.txt" "GNUMakefile" "Makefile" "debian/control" "WORKSPACE" "flake.nix" "default.nix" "meson.build" "SConstruct" "?*.sln" "?*.fsproj" "?*.csproj" "GTAGS" "TAGS" "configure.ac" "configure.in" ...) :if #f(compiled-function (f) #<bytecode -0x35b48e202190b>))
apply(cl-position nil ("dune-project" "pubspec.yaml" "info.rkt" "Cargo.toml" "stack.yaml" "DESCRIPTION" "Eldev" "Cask" "shard.yml" "Gemfile" ".bloop" "deps.edn" "build.boot" "project.clj" "build.sc" "build.sbt" "application.yml" "gradlew" "build.gradle" "pom.xml" "poetry.lock" "Pipfile" "tox.ini" "setup.py" "requirements.txt" "manage.py" "angular.json" "package.json" "gulpfile.js" "Gruntfile.js" "mix.exs" "rebar.config" "composer.json" "Taskfile.yml" "CMakeLists.txt" "GNUMakefile" "Makefile" "debian/control" "WORKSPACE" "flake.nix" "default.nix" "meson.build" "SConstruct" "?*.sln" "?*.fsproj" "?*.csproj" "GTAGS" "TAGS" "configure.ac" "configure.in" ...) (:if #f(compiled-function (f) #<bytecode -0x35b48e202190b>)))
cl-find(nil ("dune-project" "pubspec.yaml" "info.rkt" "Cargo.toml" "stack.yaml" "DESCRIPTION" "Eldev" "Cask" "shard.yml" "Gemfile" ".bloop" "deps.edn" "build.boot" "project.clj" "build.sc" "build.sbt" "application.yml" "gradlew" "build.gradle" "pom.xml" "poetry.lock" "Pipfile" "tox.ini" "setup.py" "requirements.txt" "manage.py" "angular.json" "package.json" "gulpfile.js" "Gruntfile.js" "mix.exs" "rebar.config" "composer.json" "Taskfile.yml" "CMakeLists.txt" "GNUMakefile" "Makefile" "debian/control" "WORKSPACE" "flake.nix" "default.nix" "meson.build" "SConstruct" "?*.sln" "?*.fsproj" "?*.csproj" "GTAGS" "TAGS" "configure.ac" "configure.in" ...) :if #f(compiled-function (f) #<bytecode -0x35b48e202190b>))
apply(cl-find nil ("dune-project" "pubspec.yaml" "info.rkt" "Cargo.toml" "stack.yaml" "DESCRIPTION" "Eldev" "Cask" "shard.yml" "Gemfile" ".bloop" "deps.edn" "build.boot" "project.clj" "build.sc" "build.sbt" "application.yml" "gradlew" "build.gradle" "pom.xml" "poetry.lock" "Pipfile" "tox.ini" "setup.py" "requirements.txt" "manage.py" "angular.json" "package.json" "gulpfile.js" "Gruntfile.js" "mix.exs" "rebar.config" "composer.json" "Taskfile.yml" "CMakeLists.txt" "GNUMakefile" "Makefile" "debian/control" "WORKSPACE" "flake.nix" "default.nix" "meson.build" "SConstruct" "?*.sln" "?*.fsproj" "?*.csproj" "GTAGS" "TAGS" "configure.ac" "configure.in" ...) :if #f(compiled-function (f) #<bytecode -0x35b48e202190b>) nil)
cl-find-if(#f(compiled-function (f) #<bytecode -0x35b48e202190b>) ("dune-project" "pubspec.yaml" "info.rkt" "Cargo.toml" "stack.yaml" "DESCRIPTION" "Eldev" "Cask" "shard.yml" "Gemfile" ".bloop" "deps.edn" "build.boot" "project.clj" "build.sc" "build.sbt" "application.yml" "gradlew" "build.gradle" "pom.xml" "poetry.lock" "Pipfile" "tox.ini" "setup.py" "requirements.txt" "manage.py" "angular.json" "package.json" "gulpfile.js" "Gruntfile.js" "mix.exs" "rebar.config" "composer.json" "Taskfile.yml" "CMakeLists.txt" "GNUMakefile" "Makefile" "debian/control" "WORKSPACE" "flake.nix" "default.nix" "meson.build" "SConstruct" "?*.sln" "?*.fsproj" "?*.csproj" "GTAGS" "TAGS" "configure.ac" "configure.in" ...))
#f(compiled-function (dir) #<bytecode -0x1af6462017d34c78>)("~/TEMP/hidden/")
projectile-locate-dominating-file("/home/fleury/TEMP/hidden/OrgFiles-priv/" #f(compiled-function (dir) #<bytecode -0x1af6462017d34c78>))
projectile-root-top-down("/home/fleury/TEMP/hidden/my_project/")
#f(compiled-function (func) #<bytecode -0x1a666cea8f11cd91>)(projectile-root-top-down)
cl-some(#f(compiled-function (func) #<bytecode -0x1a666cea8f11cd91>) (projectile-root-local projectile-root-marked projectile-root-bottom-up projectile-root-top-down projectile-root-top-down-recurring))
projectile-project-root()
projectile-project-name()
projectile-default-mode-line()
projectile-update-mode-line()
projectile-find-file-hook-function()
run-hooks(find-file-hook)
after-find-file(nil t)
find-file-noselect-1(#<buffer theater.org> "~/TEMP/hidden/my_project/readme.org" nil nil "~/TEMP/hidden/my_project/readme.org" (18482647 65025))
find-file-noselect("/home/fleury/TEMP/hidden/my_project/readme.org" nil nil nil)
find-file("/home/fleury/TEMP/hidden/my_project/readme.org")
dired--find-file(find-file "/home/fleury/TEMP/hidden/my_project/readme.org")
dired--find-possibly-alternative-file("/home/fleury/TEMP/hidden/my_project/readme.org")
dired-find-file()
funcall-interactively(dired-find-file)
#<subr call-interactively>(dired-find-file nil nil)
apply(#<subr call-interactively> dired-find-file (nil nil))
call-interactively@ido-cr+-record-current-command(#<subr call-interactively> dired-find-file nil nil)
apply(call-interactively@ido-cr+-record-current-command #<subr call-interactively> (dired-find-file nil nil))
call-interactively(dired-find-file nil nil)
command-execute(dired-find-file)
I get the wanted behavior in adding ignore-errors in this function:
(defun projectile-expand-file-name-wildcard (name-pattern dir)
"...."
(let ((expanded (expand-file-name name-pattern dir)))
(or (if (string-match-p "[[*?]" name-pattern)
(car
(ignore-errors ;; <===== I added this
(file-expand-wildcards expanded))))
expanded)))
Environment & Version information
Projectile version information
Projectile version: 20221122.2032
Commit: 14beeaee7a77601aee4d4982811f6a27f696403c
Emacs version
GNU Emacs 28.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.34, cairo version 1.16.0) of 2022-12-02, modified by Debian
Operating system
Linux Debian
I have exactly the same problem when opening /tmp/user/1000/test when permissions looks like this
drwx--x--x 3 root root 60 Oct 5 19:33 /tmp/user
drwx------ 2 tcech users 40 Oct 5 19:36 /tmp/user/1000
This is easy to trigger on macOS when you have opened a file in a restricted directory such as iCloud Drive (you can open a specific iCloud Drive file in Emacs, but Emacs can't enumerate the content of the ~/Library/Mobile Documents/com~apple~CloudDocs/Docs directory).
I am working around this with the following advice:
(defun my-safe-projectile-expand-file-name-wildcard (old-func &rest args)
"Swallow errors and return the same fallback as original function."
(condition-case nil
(apply old-func args)
(file-error (expand-file-name (car args) (cadr args)))))
(advice-add #'projectile-expand-file-name-wildcard :around #'my-safe-projectile-expand-file-name-wildcard)