Repository: watchexec/cargo-watch

Issue #135: Error when containing a non accessable directory
Created: 2019-11-05T07:34:05Z
I've tried to use cargo-watch in my project.
As I'm using docker-compose for my database, there is a folder which is only accessible by root with my configuration which is also in .gitignore. I also tried to exclude this directory with the ignore-argument.
However, when executing cargo-watch I'm getting this error:
Error: I/O error: Permission denied (os error 13)

I think that the tool should also run with such files/folders inside my project.
I've fixed it temporarly with chmod -R 777 but I don't think that is the way to go.
If this issue is accepted to be fixed I would be happy to contribute that part 👍
debug output:
$ cargo watch --debug -x run
>>> Load Git/VCS ignores: true
>>> Default ignores: ["*/.DS_Store", "*.sw?", "*.sw?x", "#*#", ".#*", ".*.kate-swp", "*/.hg/**", "*/.git/**", "*/.svn/**", "*.db", "*.db-*", "*/*.db-journal/**", "*/target/**"]
>>> All ignores: ["*/.DS_Store", "*.sw?", "*.sw?x", "#*#", ".#*", ".*.kate-swp", "*/.hg/**", "*/.git/**", "*/.svn/**", "*.db", "*.db-*", "*/*.db-journal/**", "*/target/**"]
>>> File updates debounce: 0.5 seconds
>>> Commands: ["cargo run"]
>>> Watches: ["."]
>>> Watchexec arguments: Args { cmd: ["cargo run"], paths: ["."], filters: [], ignores: ["*/.DS_Store", "*.sw?", "*.sw?x", "#*#", ".#*", ".*.kate-swp", "*/.hg/**", "*/.git/**", "*/.svn/**", "*.db", "*.db-*", "*/*.db-journal/**", "*/target/**"], clear_screen: false, signal: None, restart: true, debounce: 500, debug: true, run_initially: true, no_shell: false, no_vcs_ignore: false, no_ignore: false, once: false, poll: false, poll_interval: 500 }
*** glob converted to regex: Glob { glob: "target/**", re: "(?-u)^target(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: true, backslash_escape: true }, tokens: Tokens([Literal('t'), Literal('a'), Literal('r'), Literal('g'), Literal('e'), Literal('t'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "**/*.rs.bk/**", re: "(?-u)^(?:/?|.*/)[^/]*\\.rs\\.bk(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: true, backslash_escape: true }, tokens: Tokens([RecursivePrefix, ZeroOrMore, Literal('.'), Literal('r'), Literal('s'), Literal('.'), Literal('b'), Literal('k'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "**/db/**", re: "(?-u)^(?:/?|.*/)db(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: true, backslash_escape: true }, tokens: Tokens([RecursivePrefix, Literal('d'), Literal('b'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "**/world.txt/**", re: "(?-u)^(?:/?|.*/)world\\.txt(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: true, backslash_escape: true }, tokens: Tokens([RecursivePrefix, Literal('w'), Literal('o'), Literal('r'), Literal('l'), Literal('d'), Literal('.'), Literal('t'), Literal('x'), Literal('t'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "**/.env/**", re: "(?-u)^(?:/?|.*/)\\.env(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: true, backslash_escape: true }, tokens: Tokens([RecursivePrefix, Literal('.'), Literal('e'), Literal('n'), Literal('v'), RecursiveSuffix]) }
*** built glob set; 0 literals, 0 basenames, 0 extensions, 0 prefixes, 0 suffixes, 0 required extensions, 5 regexes
*** Loaded "/home/maex/projects/own/cronjob-as-a-service/.gitignore"
*** Adding ignore: "*/.DS_Store"
*** Adding ignore: "*.sw?"
*** Adding ignore: "*.sw?x"
*** Adding ignore: "**/#*#"
*** Adding ignore: "**/.#*"
*** Adding ignore: "**/.*.kate-swp"
*** Adding ignore: "*/.hg/**"
*** Adding ignore: "*/.git/**"
*** Adding ignore: "*/.svn/**"
*** Adding ignore: "*.db"
*** Adding ignore: "*.db-*"
*** Adding ignore: "*/*.db-journal/**"
*** Adding ignore: "*/target/**"
*** glob converted to regex: Glob { glob: "*.sw?", re: "(?-u)^.*\\.sw.$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('.'), Literal('s'), Literal('w'), Any]) }
*** glob converted to regex: Glob { glob: "*.sw?x", re: "(?-u)^.*\\.sw.x$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('.'), Literal('s'), Literal('w'), Any, Literal('x')]) }
*** glob converted to regex: Glob { glob: "**/#*#", re: "(?-u)^(?:/?|.*/)\\#.*\\#$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([RecursivePrefix, Literal('#'), ZeroOrMore, Literal('#')]) }
*** glob converted to regex: Glob { glob: "**/.#*", re: "(?-u)^(?:/?|.*/)\\.\\#.*$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([RecursivePrefix, Literal('.'), Literal('#'), ZeroOrMore]) }
*** glob converted to regex: Glob { glob: "*/.hg/**", re: "(?-u)^.*/\\.hg(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('/'), Literal('.'), Literal('h'), Literal('g'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "*/.git/**", re: "(?-u)^.*/\\.git(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('/'), Literal('.'), Literal('g'), Literal('i'), Literal('t'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "*/.svn/**", re: "(?-u)^.*/\\.svn(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('/'), Literal('.'), Literal('s'), Literal('v'), Literal('n'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "*.db-*", re: "(?-u)^.*\\.db\\-.*$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('.'), Literal('d'), Literal('b'), Literal('-'), ZeroOrMore]) }
*** glob converted to regex: Glob { glob: "*/*.db-journal/**", re: "(?-u)^.*/.*\\.db\\-journal(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('/'), ZeroOrMore, Literal('.'), Literal('d'), Literal('b'), Literal('-'), Literal('j'), Literal('o'), Literal('u'), Literal('r'), Literal('n'), Literal('a'), Literal('l'), RecursiveSuffix]) }
*** glob converted to regex: Glob { glob: "*/target/**", re: "(?-u)^.*/target(?:/?|/.*)$", opts: GlobOptions { case_insensitive: false, literal_separator: false, backslash_escape: true }, tokens: Tokens([ZeroOrMore, Literal('/'), Literal('t'), Literal('a'), Literal('r'), Literal('g'), Literal('e'), Literal('t'), RecursiveSuffix]) }
*** built glob set; 0 literals, 0 basenames, 1 extensions, 0 prefixes, 1 suffixes, 1 required extensions, 10 regexes
Error: I/O error: Permission denied (os error 13)

Duplicate issue #146: permissions on ignored directory not permitting enumeration result in immediate exit
Created: 2020-05-15T17:42:25Z
So this is a bunch of interacting issues, which may be related to watchexec more than cargo-watch, but I'm experiencing them using cargo-watch so I'm adding this here initially

subdirectories, even if they are (based on the ignore files/patterns) always going to have all their files ignored, have a inotify watch added and are enumerated.
when one of these subdirectories happens to have permissions that forbid enumeration for the user running cargo-watch, a very terse error message is emitted and cargo-watch exits:

Error: I/O error: Permission denied (os error 13)


strace -ff can be used to track down the offending file.

This could probably be fixed/improved in a few ways:

warn, but don't exit on permissions issues when enumerating files
emit a file path
avoid enumerating into ignored directories that lack ignore

Closing comment (2020-05-20T23:48:27Z): Agreed, part is a dup of #135.
On the "inotify watches happening even on ignored directories", I noticed this issue (with permissions) due to some build directories (generated by bazel and included in the ignores) lacking x permissions.
I've looked a bit, and I think the core issue is that watchexec relies on notify's recursive watch support, which doesn't consult the ignores and adds watches for all subdirectories (https://github.com/watchexec/watchexec/blob/f8f6c0ac5ab184e9153e8118635de758cbdae704/src/watcher.rs#L35, https://github.com/notify-rs/notify/blob/eed64ac9088ec1aab5c4710ef7232f0fbee49e0a/src/inotify.rs#L411-L422 )
An option is likely just enumerating paths ourselves, applying ignores, and using non-recursive watch mechanisms, though this may not map well to other platforms (and there's also the caveat that there might be directories that don't yet exist but would be exempt from the ignores, requiring the registration of an inotify watch on their ignored parent directory)