From 06be2107afa6f56b3740aaee0e0bc73067a933dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81my=20Coutable?= <rymai@rymai.me> Date: Thu, 21 Jul 2011 01:40:40 +0200 Subject: [PATCH] Dir.glob now ignores files that don't need to be watched By default, we don't watch ., .., .bundle, .git (this is HUGE), log, tmp and vendor (this is also HUGE). Also don't append '/' to the dir given to Guard::Listener#potentially_modified_files, the method now handles it internally. In my case, Guard::Listener#potentially_modified_files was taking ~56 seconds (in a big Rails project), it takes now... less than 1 second. Enjoy. --- lib/guard/listener.rb | 22 ++++++++++++++++++---- lib/guard/listeners/polling.rb | 2 +- lib/guard/listeners/windows.rb | 1 - spec/guard/listener_spec.rb | 16 ++++++++-------- spec/guard/listeners/darwin_spec.rb | 2 -- spec/guard/listeners/linux_spec.rb | 1 - spec/guard/listeners/polling_spec.rb | 6 ++---- spec/guard/listeners/windows_spec.rb | 1 - spec/support/listener_helper.rb | 11 ++++++----- 9 files changed, 35 insertions(+), 27 deletions(-) diff --git a/lib/guard/listener.rb b/lib/guard/listener.rb index b06aad5..ae8b07a 100644 --- a/lib/guard/listener.rb +++ b/lib/guard/listener.rb @@ -61,7 +61,7 @@ module Guard end def all_files - potentially_modified_files [directory + '/'], :all => true + potentially_modified_files([@directory], :all => true) end # scopes all given paths to the current #directory @@ -78,9 +78,23 @@ module Guard private - def potentially_modified_files(dirs, options = {}) - match = options[:all] ? "**/*" : "*" - Dir.glob(dirs.map { |dir| "#{dir}#{match}" }, File::FNM_DOTMATCH).select { |file| File.file?(file) } + def potentially_modified_files(dirs, options={}) + paths = Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path| + %w[. .. .bundle .git log tmp vendor].include?(File.basename(path)) + end + + if options[:all] + paths.inject([]) do |array, path| + if File.file?(path) + array << path + else + array += Dir.glob("#{path}/**/*", File::FNM_DOTMATCH).select { |p| File.file?(p) } + end + array + end + else + paths.select { |path| File.file?(path) } + end end # Depending on the filesystem, mtime is probably only precise to the second, so round diff --git a/lib/guard/listeners/polling.rb b/lib/guard/listeners/polling.rb index 1c9b0db..fad687c 100644 --- a/lib/guard/listeners/polling.rb +++ b/lib/guard/listeners/polling.rb @@ -22,7 +22,7 @@ module Guard def watch_change until @stop start = Time.now.to_f - files = modified_files([Dir.pwd + '/'], :all => true) + files = modified_files([Dir.pwd], :all => true) @callback.call(files) unless files.empty? nap_time = @latency - (Time.now.to_f - start) sleep(nap_time) if nap_time > 0 diff --git a/lib/guard/listeners/windows.rb b/lib/guard/listeners/windows.rb index 64af05c..f6ca03a 100644 --- a/lib/guard/listeners/windows.rb +++ b/lib/guard/listeners/windows.rb @@ -33,7 +33,6 @@ module Guard def watch(directory) worker.watch(directory, :all_events, :recursive) do |event| - paths = [File.expand_path(event.watcher.path) + '/'] paths = [File.expand_path(event.watcher.path)] files = modified_files(paths, :all => true) @callback.call(files) unless files.empty? diff --git a/spec/guard/listener_spec.rb b/spec/guard/listener_spec.rb index 6eb675a..e9ae26b 100644 --- a/spec/guard/listener_spec.rb +++ b/spec/guard/listener_spec.rb @@ -32,9 +32,9 @@ describe Guard::Listener do subject.stub!(:mac?).and_return(true) Guard::Darwin.stub!(:usable?).and_return(true) - path, opts = 'path', {:foo => 23} + path, opts = 'path', { :foo => 23 } Guard::Darwin.should_receive(:new).with(path, opts).and_return(true) - subject.select_and_init path, opts + subject.select_and_init(path, opts) end end @@ -90,24 +90,24 @@ describe Guard::Listener do context "without the :all option" do it "finds modified files only in the directory supplied" do FileUtils.touch([file1, file2, file3]) - subject.modified_files([@fixture_path.join("folder1/")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"] + subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"] end end context "with the :all options" do it "finds modified files within subdirectories" do FileUtils.touch([file1, file2, file3]) - subject.modified_files([@fixture_path.join("folder1/")], { :all => true }).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt", "spec/fixtures/folder1/folder2/file2.txt"] + subject.modified_files([@fixture_path.join("folder1")], { :all => true }).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt", "spec/fixtures/folder1/folder2/file2.txt"] end end context "without updating the content" do it "ignores the files for the second time" do FileUtils.touch([file1, file2, file3]) - subject.modified_files([@fixture_path.join("folder1/")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"] + subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"] subject.update_last_event FileUtils.touch([file1, file2, file3]) - subject.modified_files([@fixture_path.join("folder1/")], {}).should == [] + subject.modified_files([@fixture_path.join("folder1")], {}).should be_empty sleep 1 end end @@ -117,11 +117,11 @@ describe Guard::Listener do it "identifies the files for the second time" do FileUtils.touch([file1, file2, file3]) - subject.modified_files([@fixture_path.join("folder1/")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"] + subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"] subject.update_last_event FileUtils.touch([file2, file3]) File.open(file1, "w") { |f| f.write("changed content") } - subject.modified_files([@fixture_path.join("folder1/")], {}).should =~ ["spec/fixtures/folder1/file1.txt"] + subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/file1.txt"] sleep 1 end end diff --git a/spec/guard/listeners/darwin_spec.rb b/spec/guard/listeners/darwin_spec.rb index 25c26f3..1b679bb 100644 --- a/spec/guard/listeners/darwin_spec.rb +++ b/spec/guard/listeners/darwin_spec.rb @@ -23,7 +23,5 @@ describe Guard::Darwin do it_should_behave_like "a listener that reacts to #on_change" it_should_behave_like "a listener scoped to a specific directory" - end - end diff --git a/spec/guard/listeners/linux_spec.rb b/spec/guard/listeners/linux_spec.rb index c6ea166..8bd1598 100644 --- a/spec/guard/listeners/linux_spec.rb +++ b/spec/guard/listeners/linux_spec.rb @@ -74,5 +74,4 @@ describe Guard::Linux do end end - end diff --git a/spec/guard/listeners/polling_spec.rb b/spec/guard/listeners/polling_spec.rb index 90d389f..072421e 100644 --- a/spec/guard/listeners/polling_spec.rb +++ b/spec/guard/listeners/polling_spec.rb @@ -2,10 +2,8 @@ require 'spec_helper' require 'guard/listeners/polling' describe Guard::Polling do - subject { Guard::Polling } - it_should_behave_like "a listener that reacts to #on_change" - it_should_behave_like "a listener scoped to a specific directory" - + it_should_behave_like "a listener that reacts to #on_change" + it_should_behave_like "a listener scoped to a specific directory" end diff --git a/spec/guard/listeners/windows_spec.rb b/spec/guard/listeners/windows_spec.rb index 133dc83..f59cf55 100644 --- a/spec/guard/listeners/windows_spec.rb +++ b/spec/guard/listeners/windows_spec.rb @@ -25,5 +25,4 @@ describe Guard::Windows do it_should_behave_like "a listener scoped to a specific directory" end - end diff --git a/spec/support/listener_helper.rb b/spec/support/listener_helper.rb index b52bd5d..03bc21b 100644 --- a/spec/support/listener_helper.rb +++ b/spec/support/listener_helper.rb @@ -53,7 +53,7 @@ shared_examples_for 'a listener that reacts to #on_change' do file = @fixture_path.join("folder1/file1.txt") File.exists?(file).should be_true start - File.open(file, 'w') {|f| f.write('') } + File.open(file, 'w') { |f| f.write('') } stop results.should =~ ['spec/fixtures/folder1/file1.txt'] end @@ -62,7 +62,7 @@ shared_examples_for 'a listener that reacts to #on_change' do file = @fixture_path.join(".dotfile") File.exists?(file).should be_true start - File.open(file, 'w') {|f| f.write('') } + File.open(file, 'w') { |f| f.write('') } stop results.should =~ ['spec/fixtures/.dotfile'] end @@ -73,8 +73,8 @@ shared_examples_for 'a listener that reacts to #on_change' do File.exists?(file1).should be_true File.exists?(file2).should be_true start - File.open(file1, 'w') {|f| f.write('') } - File.open(file2, 'w') {|f| f.write('') } + File.open(file1, 'w') { |f| f.write('') } + File.open(file2, 'w') { |f| f.write('') } stop results.should =~ ['spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/folder2/file2.txt'] end @@ -108,6 +108,7 @@ shared_examples_for "a listener scoped to a specific directory" do @wd = @fixture_path.join("folder1") @listener = described_class.new @wd end + it "should base paths within this directory" do record_results new_file = @wd.join("folder2/newfile.rb") @@ -116,7 +117,7 @@ shared_examples_for "a listener scoped to a specific directory" do File.exists?(new_file).should be_false start FileUtils.touch new_file - File.open(modified, 'w') {|f| f.write('') } + File.open(modified, 'w') { |f| f.write('') } stop File.delete new_file results.should =~ ["folder2/newfile.rb", 'file1.txt']