Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Listen on Rails root spams errors on local symlinks #8

Open
wjordan opened this issue Aug 19, 2015 · 8 comments
Open

Using Listen on Rails root spams errors on local symlinks #8

wjordan opened this issue Aug 19, 2015 · 8 comments

Comments

@wjordan
Copy link

wjordan commented Aug 19, 2015

Hello, I'm attempting to use spring-watcher-listen in a large Rails project containing several local symlinks, all of which serve a specific purpose and cannot be removed. Using spring-watcher-listen with recent versions of listen (since guard/listen#273), loading spring spams the following error once for every local symlink in the project:

        ** ERROR: directory is already being watched! **

        Directory: [path]/dir

        is already begin watched through: [path]/dir

        MORE INFO: https://github.com/guard/listen/wiki/Duplicate-directory-errors

In response to the issue guard/listen#339 I opened, @e2 suggested that my case might in fact be better solved by patching spring-watcher-listen to call that library more appropriately:

I'm also pretty sure the spring Listen watcher doesn't need to watch the
whole project - so maybe it needs to be patched instead.

Does this suggestion sound correct? If so, any ideas on whether/how it would be possible to patch this library to watch a more selective set of files, in order to resolve this local-symlink error-spam issue in recent versions of Listen?

@e2
Copy link
Contributor

e2 commented Aug 19, 2015

https://github.com/jonleighton/spring-watcher-listen/blob/master/lib/spring/watcher/listen.rb#L58

You can probably try monkey patching this method to set your own set of dirs to avoid rewatching the symlinked dirs.

@wjordan
Copy link
Author

wjordan commented Aug 20, 2015

Thanks for the suggestion @e2. I spent some time trying the suggested patch, but unfortunately it looks like avoiding a watch on the project root is not possible. Spring must watch Gemfile for changes in the project root directory, and since (as far as I can tell) the Listen API doesn't watch individual files for changes but only recursively watches directory trees, this means the only way to watch Gemfile for changes is to recursively watch the root project.

@wjordan
Copy link
Author

wjordan commented Aug 20, 2015

Actually, I managed to workaround the Gemfile recursive-watch constraints by moving Gemfile and Gemfile.lock into a subfolder and adding a symlink to their expected location, e.g.:

mkdir .Gemfile
mv Gemfile* .Gemfile/
ln -s .Gemfile/Gemfile Gemfile
ln -s .Gemfile/Gemfile.lock Gemfile.lock

Along with this monkey-patch that removes the root from the base_directories array:

# Monkey-patch spring-watcher-listen to not watch the project root by default
require 'spring/watcher/listen'
module Spring
  module Watcher
    class Listen < Abstract
      def base_directories
        (files.map { |f| File.expand_path("#{f}/..") } +
          directories.to_a
        ).uniq.map { |path| Pathname.new(path) }
      end
    end
  end
end

This allows my project to successfully load spring-watcher-listen without the error spam and without suppressing the errors directly. I look forward to ideas on how to incorporate these fixes into a cleaner, less-hacky solution.

wjordan added a commit to code-dot-org/code-dot-org that referenced this issue Aug 20, 2015
- Move Gemfile, Gemfile.lock, deployment.rb out of project root via symlink (cf. guard/listen#273)
@e2
Copy link
Contributor

e2 commented Aug 20, 2015

Looks really good to me - guard-bundler actually does something simillar (expects Gemfile symlinked from config directory - or warning if not).

Removing watching the root directory is the right way to avoid performance problems on OSX, because sadly rb-fsevent is recursive.

In fact, the reason to use symlinks is to avoid watching the root directory for large Rails projects on OSX.

Summary: OSX-specific optimizations in Listen can mitigate the performance problems - and this would remove the need for warnings to begin with. Polling has a similar problem, though.

@goncalvesjoao
Copy link

Hi guys, I had the same problem that @wjordan had and after an unsuccessful monkey patch I ended up in here.

Should I be looking at guard/listen instead?

@e2
Copy link
Contributor

e2 commented Apr 13, 2016

@goncalvesjoao - figure out a way to not watch symlinked directories. I don't know what your project layout is, so I can't help much.

There might be a better way of organizing your project - but that's project specific. (E.g. why exactly do you need symlinks? Maybe you can configure one tool to reference the original files instead of telling it to use the symlinked location?).

As a quick (but detrimental?) workaround, just copy the files physically instead of symlinking them.

In short: watching directories and their symlinked version isn't supported. It's complex - rocket-science level. (It's impossible to handle symlinks in a way to make everyone happy).

So the rule of thumb is: avoid using symlinks when watching files.

(The other option is: you can hire someone to add support for your exact situation in Listen - just saying it's ungrateful work otherwise).

@ybart
Copy link

ybart commented Jul 28, 2017

I had the following error on my development environment:

        ** ERROR: directory is already being watched! **

        Directory: ./vendor/cache/rails-6f9b01c056cd/activerecord/test/fixtures/all/admin

        is already being watched through: ./vendor/cache/rails-6f9b01c056cd/activerecord/test/fixtures/to_be_linked

        MORE INFO: https://github.com/guard/listen/wiki/Duplicate-directory-errors

I solved it by removing my local bundler cache:

bundle config --delete BUNDLE_CACHE_ALL
rm -rf vendor/cache/

@jdabrowski1337
Copy link

jdabrowski1337 commented Jul 15, 2020

I was able to get rid of the errors by using this monkey patch:

require 'listen/record/symlink_detector'
module Listen
  class Record
    class SymlinkDetector
      def _fail(_, _)
        raise Error, "Don't watch locally-symlinked directory"
      end
    end
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants