filewatcher 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +38 -23
- data/Rakefile +9 -0
- data/bin/filewatcher +26 -4
- data/lib/filewatcher.rb +33 -11
- data/test/test_filewatcher.rb +11 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e284fa33515d0d74bc7cf8ddc014678e14f3700
|
4
|
+
data.tar.gz: 55d15b651a1246f50f1982ceab55a51afb5c5477
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 623df61d04ce2ab7b920d1718ddfbf7ac1791f617b17bac3e740a9b72235c9dabb0ea3824afe16cf07ac6d5e5391b4e41663c58701dcf465811c1e7c98044d4c
|
7
|
+
data.tar.gz: 4564616b0ecc6d8cdb781ea9d84790c2a60c3c89cb63f5cf915cefaf5810369b00e13c78fc3c2fee532a0d69b576d56666f252a19e542a11a129ae98dbe1d9c2
|
data/README.md
CHANGED
@@ -6,13 +6,9 @@ Filewatcher
|
|
6
6
|
[![Dependency Status](https://gemnasium.com/thomasfl/filewatcher.png?travis)](https://gemnasium.com/thomasfl/filewatcher)
|
7
7
|
[![Code Climate](https://codeclimate.com/github/thomasfl/filewatcher.png)](https://codeclimate.com/github/thomasfl/filewatcher)
|
8
8
|
|
9
|
-
Lightweight filewatcher weighing less than 200 LoC. No dependencies or platform specific code.
|
10
|
-
Works everywhere. Monitors changes in the filesystem by polling. Has no config files.
|
11
|
-
When running filewatcher from the command line, you specify which files to monitor and what action
|
12
|
-
to perform on updates.
|
9
|
+
Lightweight filewatcher weighing less than 200 LoC. No dependencies or platform specific code. Works everywhere. Monitors changes in the filesystem by polling. Has no config files. When running filewatcher from the command line, you specify which files to monitor and what action to perform on updates.
|
13
10
|
|
14
|
-
For example to search recursively for javascript files and run jshint when a file is
|
15
|
-
updated, added, renamed or deleted:
|
11
|
+
For example to search recursively for javascript files and run jshint when a file is updated, added, renamed or deleted:
|
16
12
|
|
17
13
|
Linux/OSX:
|
18
14
|
|
@@ -60,7 +56,7 @@ In Linux/OSX:
|
|
60
56
|
|
61
57
|
Place filenames or filenames in quotes to use ruby filename globbing instead
|
62
58
|
of shell filename globbing. This will make filewatcher look for files in
|
63
|
-
subdirectories too. To watch all javascript files in subdirectories:
|
59
|
+
subdirectories too. To watch all javascript files in subdirectories in Windows:
|
64
60
|
|
65
61
|
> filewatcher "**/*.js" "node %FILENAME%"
|
66
62
|
|
@@ -77,7 +73,7 @@ python, ruby, perl, php, javascript or awk script.
|
|
77
73
|
Print a list of all files matching *.css first and then output the filename
|
78
74
|
when a file is beeing updated by using the --list/-l option:
|
79
75
|
|
80
|
-
$ filewatcher -l
|
76
|
+
$ filewatcher -l '**/*.css' 'echo file: $FILENAME'
|
81
77
|
|
82
78
|
Watch the "src" and "test" folders recursively, and run test when the
|
83
79
|
filesystem gets updated:
|
@@ -93,7 +89,7 @@ The `--restart` option kills the command if it's still running when a filesystem
|
|
93
89
|
|
94
90
|
The `--dontwait` option starts the command on startup without waiting for filesystem updates. To start a webserver and have it automatically restart when html files are updated:
|
95
91
|
|
96
|
-
$ filewatcher --restart --dontwait "
|
92
|
+
$ filewatcher --restart --dontwait "**/*.html" "python -m SimpleHTTPServer"
|
97
93
|
|
98
94
|
Available enviroment variables
|
99
95
|
------------------------------
|
@@ -104,17 +100,24 @@ node whenever a javascript file is updated:
|
|
104
100
|
|
105
101
|
$ filewatcher *.js 'node $FILENAME'
|
106
102
|
|
107
|
-
|
103
|
+
Environment variables available from the command string:
|
104
|
+
|
105
|
+
BASENAME File basename.
|
106
|
+
FILENAME Relative filename.
|
107
|
+
ABSOLUTE_FILENAME Asolute filename.
|
108
|
+
RELATIVE_FILENAME Same as FILENAME but starts with "./"
|
109
|
+
EVENT Event type. Is either 'changed', 'delete' or 'new'.
|
110
|
+
DIRNAME Absolute directory name.
|
108
111
|
|
109
112
|
Command line options
|
110
113
|
--------------------
|
111
114
|
|
112
115
|
Useful command line options:
|
113
116
|
|
114
|
-
--list, -l: Print name of files
|
117
|
+
--list, -l: Print name of matching files on startup
|
115
118
|
--restart, -r: Run command in separate fork and kill it on filesystem updates
|
116
119
|
--dontwait, -d: Run the command before any filesystem updates
|
117
|
-
--spinner, -s: Display an animated spinner
|
120
|
+
--spinner, -s: Display an animated spinner while scanning
|
118
121
|
|
119
122
|
Other command line options:
|
120
123
|
|
@@ -174,21 +177,17 @@ To detect if a file is updated, added or deleted:
|
|
174
177
|
end
|
175
178
|
end
|
176
179
|
|
177
|
-
When a file is renamed it is detected as a
|
180
|
+
When a file is renamed it is detected as a new file followed by a file deletion.
|
178
181
|
|
179
|
-
|
182
|
+
The API takes some of the same options as the command line interface. To watch all files recursively except files that matches *.rb, display a spinner and only wait for 0.1 seconds between each scan:
|
180
183
|
|
181
|
-
FileWatcher.new(
|
182
|
-
|
184
|
+
FileWatcher.new('**/*.*', exclude: '**/*.rb', spinner: true, interval: 0.1).watch() do |filename|
|
185
|
+
puts filename
|
183
186
|
end
|
184
187
|
|
185
|
-
|
188
|
+
To do the same from the command line, use the same options:
|
186
189
|
|
187
|
-
|
188
|
-
puts "Updated " + filename
|
189
|
-
end
|
190
|
-
=> Watching files:
|
191
|
-
lib/filewatcher.rb
|
190
|
+
$ filewatcher '**/*.*' --exclude '**/*.rb' --spinner --interval 0.1 'echo $FILENAME'
|
192
191
|
|
193
192
|
Use patterns to match filenames in current directory and subdirectories. The
|
194
193
|
pattern is not a regular expression; instead it follows rules similar to shell
|
@@ -222,9 +221,25 @@ over the network)
|
|
222
221
|
filewatcher.finalize # Ensure all filesystem changes made prior to
|
223
222
|
# ending the watch are handled.
|
224
223
|
|
225
|
-
|
224
|
+
If basename, relative filename or absolute filename is necessay use the stanard lib 'pathname' like this:
|
225
|
+
|
226
|
+
require 'pathname'
|
227
|
+
|
228
|
+
FileWatcher.new(["**/*.*"]).watch() do |filename|
|
229
|
+
path = Pathname.new(filename)
|
230
|
+
puys "Basename : " + path.basename.to_s
|
231
|
+
puts "Relative filename: " + File.join(Pathname.new('.').to_s, path.to_s)
|
232
|
+
puts "Absolute filename: " + File.join(Pathname.new('.').realpath.to_s, path.to_s)
|
233
|
+
end
|
234
|
+
|
235
|
+
The filewatcher library is a single file with 180 LOC (including comments)
|
226
236
|
with no dependencies.
|
227
237
|
|
238
|
+
Changelog
|
239
|
+
---------
|
240
|
+
0.5.3 Exclude files. More environment variables. Options in ruby api.
|
241
|
+
0.5.2 Start, stop and finalize API.
|
242
|
+
0.5.1 Kill and restart long running command with --restart option.
|
228
243
|
|
229
244
|
Credits
|
230
245
|
-------
|
data/Rakefile
CHANGED
@@ -7,4 +7,13 @@ task :default => :test
|
|
7
7
|
desc "Run tests"
|
8
8
|
task :test do
|
9
9
|
sh "bacon -Ilib -Itest --automatic --quiet"
|
10
|
+
delete_list =
|
11
|
+
%w(test/fixtures/file3.txt
|
12
|
+
test/fixtures/file4.txt
|
13
|
+
test/fixtures/file5.txt
|
14
|
+
test/fixtures/file6.txt
|
15
|
+
test/fixtures/file7.txt)
|
16
|
+
delete_list.each do |file|
|
17
|
+
FileUtils.rm(file)
|
18
|
+
end
|
10
19
|
end
|
data/bin/filewatcher
CHANGED
@@ -20,6 +20,10 @@ Examples:
|
|
20
20
|
filewatcher "myfile" "echo 'myfile has changed'"
|
21
21
|
filewatcher '*.rb' 'ruby $FILENAME'
|
22
22
|
filewatcher '**/*.rb' 'ruby $FILENAME' # Watch subdirectories
|
23
|
+
|
24
|
+
Other available environment variables are BASENAME, ABSOLUTE_FILENAME,
|
25
|
+
RELATIVE_FILENAME, EVENT and DIRNAME.
|
26
|
+
|
23
27
|
Options:
|
24
28
|
EOS
|
25
29
|
|
@@ -74,8 +78,20 @@ if(options[:restart])
|
|
74
78
|
child_pid = nil
|
75
79
|
end
|
76
80
|
|
81
|
+
if(options[:exclude] != "")
|
82
|
+
options[:exclude] = split_files_void_escaped_whitespace(options[:exclude].split(" "))
|
83
|
+
end
|
84
|
+
|
77
85
|
begin
|
78
|
-
fw = FileWatcher.new(files, options
|
86
|
+
fw = FileWatcher.new(files, options)
|
87
|
+
|
88
|
+
if(options[:list])
|
89
|
+
puts 'Watching:'
|
90
|
+
fw.last_found_filenames.each do |filename|
|
91
|
+
puts " #{filename}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
79
95
|
fw.watch(options[:interval]) do |filename, event|
|
80
96
|
cmd = nil
|
81
97
|
if(options[:exec] and File.exist?(filename))
|
@@ -104,10 +120,16 @@ begin
|
|
104
120
|
if(cmd)
|
105
121
|
path = Pathname.new(filename)
|
106
122
|
env = {
|
107
|
-
'FILENAME'=>
|
108
|
-
'
|
109
|
-
'
|
123
|
+
'FILENAME' => filename,
|
124
|
+
'BASENAME' => path.basename.to_s,
|
125
|
+
'FILEDIR' => File.join(Pathname.new('.').realpath.to_s, path.parent.to_s), # Deprecated
|
126
|
+
'FSEVENT' => event.to_s, # Deprecated,
|
127
|
+
'EVENT' => event.to_s,
|
128
|
+
'DIRNAME' => File.join(Pathname.new('.').realpath.to_s, path.parent.to_s),
|
129
|
+
'ABSOLUTE_FILENAME' => File.join(Pathname.new('.').realpath.to_s, path.to_s),
|
130
|
+
'RELATIVE_FILENAME' => File.join(Pathname.new('.').to_s, path.to_s)
|
110
131
|
}
|
132
|
+
|
111
133
|
if(event != :delete)
|
112
134
|
ENV['FILEPATH'] = path.realpath.to_s
|
113
135
|
end
|
data/lib/filewatcher.rb
CHANGED
@@ -6,7 +6,7 @@ class FileWatcher
|
|
6
6
|
attr_accessor :filenames
|
7
7
|
|
8
8
|
def self.VERSION
|
9
|
-
return '0.5.
|
9
|
+
return '0.5.3'
|
10
10
|
end
|
11
11
|
|
12
12
|
def update_spinner(label)
|
@@ -15,26 +15,31 @@ class FileWatcher
|
|
15
15
|
print "#{' ' * 30}\r#{label} #{@spinner.rotate!.first}\r"
|
16
16
|
end
|
17
17
|
|
18
|
-
def initialize(unexpanded_filenames,
|
18
|
+
def initialize(unexpanded_filenames, *args)
|
19
|
+
if(args.first)
|
20
|
+
options = args.first
|
21
|
+
else
|
22
|
+
options = {}
|
23
|
+
end
|
19
24
|
@unexpanded_filenames = unexpanded_filenames
|
25
|
+
@unexpanded_excluded_filenames = options[:exclude]
|
20
26
|
@filenames = nil
|
21
27
|
@stored_update = nil
|
22
28
|
@keep_watching = false
|
23
29
|
@pausing = false
|
24
30
|
@last_snapshot = mtime_snapshot
|
25
31
|
@end_snapshot = nil
|
26
|
-
@dontwait = dontwait
|
27
|
-
@show_spinner =
|
28
|
-
|
29
|
-
@filenames.each do |filename|
|
30
|
-
raise 'File does not exist' unless File.exist?(filename)
|
31
|
-
puts filename if print_filelist
|
32
|
-
end
|
32
|
+
@dontwait = options[:dontwait]
|
33
|
+
@show_spinner = options[:spinner]
|
34
|
+
@interval = options[:interval]
|
33
35
|
end
|
34
36
|
|
35
37
|
def watch(sleep=0.5, &on_update)
|
36
38
|
trap("SIGINT") {return }
|
37
39
|
@sleep = sleep
|
40
|
+
if(@interval and @interval > 0)
|
41
|
+
@sleep = @interval
|
42
|
+
end
|
38
43
|
@stored_update = on_update
|
39
44
|
@keep_watching = true
|
40
45
|
if(@dontwait)
|
@@ -44,11 +49,11 @@ class FileWatcher
|
|
44
49
|
@end_snapshot = mtime_snapshot if @pausing
|
45
50
|
while @keep_watching && @pausing
|
46
51
|
update_spinner('Pausing')
|
47
|
-
Kernel.sleep sleep
|
52
|
+
Kernel.sleep @sleep
|
48
53
|
end
|
49
54
|
while @keep_watching && !filesystem_updated? && !@pausing
|
50
55
|
update_spinner('Watching')
|
51
|
-
Kernel.sleep sleep
|
56
|
+
Kernel.sleep @sleep
|
52
57
|
end
|
53
58
|
# test and null @updated_file to prevent yielding the last
|
54
59
|
# file twice if @keep_watching has just been set to false
|
@@ -102,6 +107,19 @@ class FileWatcher
|
|
102
107
|
def mtime_snapshot
|
103
108
|
snapshot = {}
|
104
109
|
@filenames = expand_directories(@unexpanded_filenames)
|
110
|
+
|
111
|
+
if(@unexpanded_excluded_filenames != nil and @unexpanded_excluded_filenames.size > 0)
|
112
|
+
# Remove files in the exclude filenames list
|
113
|
+
@filtered_filenames = []
|
114
|
+
@excluded_filenames = expand_directories(@unexpanded_excluded_filenames)
|
115
|
+
@filenames.each do |filename|
|
116
|
+
if(not(@excluded_filenames.include?(filename)))
|
117
|
+
@filtered_filenames << filename
|
118
|
+
end
|
119
|
+
end
|
120
|
+
@filenames = @filtered_filenames
|
121
|
+
end
|
122
|
+
|
105
123
|
@filenames.each do |filename|
|
106
124
|
mtime = File.exist?(filename) ? File.stat(filename).mtime : Time.new(0)
|
107
125
|
snapshot[filename] = mtime
|
@@ -138,6 +156,10 @@ class FileWatcher
|
|
138
156
|
return false
|
139
157
|
end
|
140
158
|
|
159
|
+
def last_found_filenames
|
160
|
+
@last_snapshot.keys
|
161
|
+
end
|
162
|
+
|
141
163
|
def expand_directories(patterns)
|
142
164
|
if(!patterns.kind_of?Array)
|
143
165
|
patterns = [patterns]
|
data/test/test_filewatcher.rb
CHANGED
@@ -27,12 +27,22 @@ describe FileWatcher do
|
|
27
27
|
lambda { |it| elements.all? { |element| it.include? element }}
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should exclude selected file patterns" do
|
31
|
+
filewatcher = FileWatcher.new(File.expand_path('test/fixtures/**/*'), exclude: [File.expand_path("test/fixtures/**/*.txt")])
|
32
|
+
filtered_fixtures =
|
33
|
+
%w(test/fixtures/file4.rb
|
34
|
+
test/fixtures/subdir/file6.rb
|
35
|
+
test/fixtures/subdir/file5.rb
|
36
|
+
test/fixtures/file3.rb)
|
37
|
+
filewatcher.filenames.should.satisfy &includes_all(filtered_fixtures.map { |it| File.expand_path(it) })
|
38
|
+
end
|
39
|
+
|
30
40
|
it "should handle absolute paths with globs" do
|
31
41
|
filewatcher = FileWatcher.new(File.expand_path('test/fixtures/**/*'))
|
32
42
|
|
33
43
|
filewatcher.filenames.should.satisfy &includes_all(fixtures.map { |it| File.expand_path(it) })
|
34
44
|
end
|
35
|
-
|
45
|
+
|
36
46
|
it "should handle globs" do
|
37
47
|
filewatcher = FileWatcher.new('test/fixtures/**/*')
|
38
48
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filewatcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Flemming
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: trollop
|