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.
This commit is contained in:
Rémy Coutable 2011-07-21 01:40:40 +02:00
parent 9cc1cf64d1
commit 06be2107af
9 changed files with 35 additions and 27 deletions

View File

@ -61,7 +61,7 @@ module Guard
end end
def all_files def all_files
potentially_modified_files [directory + '/'], :all => true potentially_modified_files([@directory], :all => true)
end end
# scopes all given paths to the current #directory # scopes all given paths to the current #directory
@ -78,9 +78,23 @@ module Guard
private private
def potentially_modified_files(dirs, options = {}) def potentially_modified_files(dirs, options={})
match = options[:all] ? "**/*" : "*" paths = Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
Dir.glob(dirs.map { |dir| "#{dir}#{match}" }, File::FNM_DOTMATCH).select { |file| File.file?(file) } %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 end
# Depending on the filesystem, mtime is probably only precise to the second, so round # Depending on the filesystem, mtime is probably only precise to the second, so round

View File

@ -22,7 +22,7 @@ module Guard
def watch_change def watch_change
until @stop until @stop
start = Time.now.to_f 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? @callback.call(files) unless files.empty?
nap_time = @latency - (Time.now.to_f - start) nap_time = @latency - (Time.now.to_f - start)
sleep(nap_time) if nap_time > 0 sleep(nap_time) if nap_time > 0

View File

@ -33,7 +33,6 @@ module Guard
def watch(directory) def watch(directory)
worker.watch(directory, :all_events, :recursive) do |event| worker.watch(directory, :all_events, :recursive) do |event|
paths = [File.expand_path(event.watcher.path) + '/']
paths = [File.expand_path(event.watcher.path)] paths = [File.expand_path(event.watcher.path)]
files = modified_files(paths, :all => true) files = modified_files(paths, :all => true)
@callback.call(files) unless files.empty? @callback.call(files) unless files.empty?

View File

@ -32,9 +32,9 @@ describe Guard::Listener do
subject.stub!(:mac?).and_return(true) subject.stub!(:mac?).and_return(true)
Guard::Darwin.stub!(:usable?).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) 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
end end
@ -90,24 +90,24 @@ describe Guard::Listener do
context "without the :all option" do context "without the :all option" do
it "finds modified files only in the directory supplied" do it "finds modified files only in the directory supplied" do
FileUtils.touch([file1, file2, file3]) 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
end end
context "with the :all options" do context "with the :all options" do
it "finds modified files within subdirectories" do it "finds modified files within subdirectories" do
FileUtils.touch([file1, file2, file3]) 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
end end
context "without updating the content" do context "without updating the content" do
it "ignores the files for the second time" do it "ignores the files for the second time" do
FileUtils.touch([file1, file2, file3]) 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 subject.update_last_event
FileUtils.touch([file1, file2, file3]) 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 sleep 1
end end
end end
@ -117,11 +117,11 @@ describe Guard::Listener do
it "identifies the files for the second time" do it "identifies the files for the second time" do
FileUtils.touch([file1, file2, file3]) 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 subject.update_last_event
FileUtils.touch([file2, file3]) FileUtils.touch([file2, file3])
File.open(file1, "w") { |f| f.write("changed content") } 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 sleep 1
end end
end end

View File

@ -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 that reacts to #on_change"
it_should_behave_like "a listener scoped to a specific directory" it_should_behave_like "a listener scoped to a specific directory"
end end
end end

View File

@ -74,5 +74,4 @@ describe Guard::Linux do
end end
end end
end end

View File

@ -2,10 +2,8 @@ require 'spec_helper'
require 'guard/listeners/polling' require 'guard/listeners/polling'
describe Guard::Polling do describe Guard::Polling do
subject { Guard::Polling } subject { Guard::Polling }
it_should_behave_like "a listener that reacts to #on_change" 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 scoped to a specific directory"
end end

View File

@ -25,5 +25,4 @@ describe Guard::Windows do
it_should_behave_like "a listener scoped to a specific directory" it_should_behave_like "a listener scoped to a specific directory"
end end
end end

View File

@ -53,7 +53,7 @@ shared_examples_for 'a listener that reacts to #on_change' do
file = @fixture_path.join("folder1/file1.txt") file = @fixture_path.join("folder1/file1.txt")
File.exists?(file).should be_true File.exists?(file).should be_true
start start
File.open(file, 'w') {|f| f.write('') } File.open(file, 'w') { |f| f.write('') }
stop stop
results.should =~ ['spec/fixtures/folder1/file1.txt'] results.should =~ ['spec/fixtures/folder1/file1.txt']
end end
@ -62,7 +62,7 @@ shared_examples_for 'a listener that reacts to #on_change' do
file = @fixture_path.join(".dotfile") file = @fixture_path.join(".dotfile")
File.exists?(file).should be_true File.exists?(file).should be_true
start start
File.open(file, 'w') {|f| f.write('') } File.open(file, 'w') { |f| f.write('') }
stop stop
results.should =~ ['spec/fixtures/.dotfile'] results.should =~ ['spec/fixtures/.dotfile']
end end
@ -73,8 +73,8 @@ shared_examples_for 'a listener that reacts to #on_change' do
File.exists?(file1).should be_true File.exists?(file1).should be_true
File.exists?(file2).should be_true File.exists?(file2).should be_true
start start
File.open(file1, 'w') {|f| f.write('') } File.open(file1, 'w') { |f| f.write('') }
File.open(file2, 'w') {|f| f.write('') } File.open(file2, 'w') { |f| f.write('') }
stop stop
results.should =~ ['spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/folder2/file2.txt'] results.should =~ ['spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/folder2/file2.txt']
end end
@ -108,6 +108,7 @@ shared_examples_for "a listener scoped to a specific directory" do
@wd = @fixture_path.join("folder1") @wd = @fixture_path.join("folder1")
@listener = described_class.new @wd @listener = described_class.new @wd
end end
it "should base paths within this directory" do it "should base paths within this directory" do
record_results record_results
new_file = @wd.join("folder2/newfile.rb") 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 File.exists?(new_file).should be_false
start start
FileUtils.touch new_file FileUtils.touch new_file
File.open(modified, 'w') {|f| f.write('') } File.open(modified, 'w') { |f| f.write('') }
stop stop
File.delete new_file File.delete new_file
results.should =~ ["folder2/newfile.rb", 'file1.txt'] results.should =~ ["folder2/newfile.rb", 'file1.txt']