file_monitoring 0.0.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/file_monitoring CHANGED
File without changes
@@ -1,12 +1,29 @@
1
1
  require 'file_monitoring/file_monitoring'
2
2
 
3
- # TODO add description
4
- module BBFS
5
- module FileMonitoring
6
- # The main method. Loops on all paths each time span and monitors them.
7
- def monitor_files
8
- fm = FileMonitoring.new
9
- fm.monitor_files
10
- end
3
+ # Daemon for monitoring directories for changes.
4
+ # Paths are checked for changes per user-defined period of time.
5
+ #
6
+ # Directory defined changed when:
7
+ # 1. Directory structure changed, i.e. sub-directories or files were added/removed
8
+ # 2. One of the files located in the directory or one of its sub-directories was changed
9
+ # 3. One of sub-directories changed (see 1. and 2. above)
10
+ #
11
+ # File monitoring controled by following configuration parameters:
12
+ # * <tt>default_monitoring_log_path</tt> - holds path of file monitoring log.
13
+ # This log containd track of changes found during monitoring
14
+ # * <tt>monitoring_paths</tt> - path and file monitoring configuration data
15
+ # regarding these paths.
16
+
17
+ module FileMonitoring
18
+ Params.path('default_monitoring_log_path', '~/.bbfs/log/file_monitoring.log',
19
+ 'Default path for file monitoring log file. ' \
20
+ 'This log containd track of changes found during monitoring')
21
+ Params.complex('monitoring_paths', nil, 'Array of Hashes with 3 fields: ' \
22
+ 'path, scan_period and stable_state.')
23
+
24
+ # @see FileMonitoring#monitor_files
25
+ def monitor_files
26
+ fm = FileMonitoring.new
27
+ fm.monitor_files
11
28
  end
12
29
  end
@@ -2,71 +2,73 @@ require 'algorithms'
2
2
  require 'fileutils'
3
3
  require 'log'
4
4
  require 'params'
5
- require 'yaml'
6
5
 
7
6
  require 'file_monitoring/monitor_path'
8
7
 
9
- module BBFS
10
- module FileMonitoring
8
+ module FileMonitoring
9
+ # Manages file monitoring of number of file system locations
10
+ class FileMonitoring
11
11
 
12
- Params.string('default_log_path', File.expand_path('~/.bbfs/log/file_monitoring.log'),
13
- 'Default path for log file.')
14
-
15
- class FileMonitoring
16
-
17
- def set_config_path(config_path)
18
- @config_path = config_path
19
- end
20
-
21
- def set_event_queue(queue)
22
- @event_queue = queue
23
- end
24
-
25
- def monitor_files
26
- config_yml = YAML::load_file(@config_path)
27
-
28
- conf_array = config_yml['paths']
29
-
30
- pq = Containers::PriorityQueue.new
31
- conf_array.each { |elem|
32
- priority = (Time.now + elem['scan_period']).to_i
33
- dir_stat = DirStat.new(elem['path'], elem['stable_state'])
34
- dir_stat.set_event_queue(@event_queue) if @event_queue
35
- Log.info [priority, elem, dir_stat]
36
- pq.push([priority, elem, dir_stat], -priority)
37
- }
38
-
39
- log_path = Params['default_log_path']
40
- if config_yml.key?('log_path')
41
- log_path = File.expand_path(config_yml['log_path'])
42
- end
43
-
44
- Log.info 'Log path:' + log_path
45
- FileUtils.mkdir_p(File.dirname(log_path))
46
- log = File.open(log_path, 'w')
47
- FileStat.set_log(log)
48
-
49
- while true do
50
- time, conf, dir_stat = pq.pop
51
- #Log.info 'time:' + time.to_s()
52
- #Log.info 'now:' + Time.now.to_i.to_s()
53
- #Log.info conf
54
-
55
- time_span = time - Time.now.to_i
56
- if (time_span > 0)
57
- sleep(time_span)
58
- end
59
- dir_stat.monitor
12
+ # Set event queue used for communication between different proceses.
13
+ # @param queue [Queue]
14
+ def set_event_queue(queue)
15
+ @event_queue = queue
16
+ end
60
17
 
61
- #Log.info conf['path']
62
- #Log.info conf['scan_period']
63
- priority = (Time.now + conf['scan_period']).to_i
64
- pq.push([priority, conf, dir_stat], -priority)
18
+ # The main method. Loops on all paths, each time span and monitors them.
19
+ #
20
+ # =Algorithm:
21
+ # There is a loop that performs at every iteration:
22
+ # 1.Pull entry with a minimal time of check from queue
23
+ # 2.Recursively check path taken from entry for changes
24
+ # a.Notify subscribed processes on changes
25
+ # 3.Push entry to the queue with new time of next check
26
+ #
27
+ # This methods controlled by <tt>monitoring_paths</tt> configuration parameter,
28
+ # that provides path and file monitoring configuration data
29
+ def monitor_files
30
+ conf_array = Params['monitoring_paths']
31
+
32
+ # Directories states stored in the priority queue,
33
+ # where the key (priority) is a time when it should be checked next time.
34
+ # Priority queue means that all entries arranged by key (time to check) in increasing order.
35
+ pq = Containers::PriorityQueue.new
36
+ conf_array.each { |elem|
37
+ priority = (Time.now + elem['scan_period']).to_i
38
+ dir_stat = DirStat.new(File.expand_path(elem['path']), elem['stable_state'])
39
+ dir_stat.set_event_queue(@event_queue) if @event_queue
40
+ Log.info "File monitoring started for: #{elem}"
41
+ pq.push([priority, elem, dir_stat], -priority)
42
+ }
43
+
44
+ log_path = Params['default_monitoring_log_path']
45
+
46
+ Log.info 'File monitoring log: ' + log_path
47
+ log_dir = File.dirname(log_path)
48
+ FileUtils.mkdir_p(log_dir) unless File.exists?(log_dir)
49
+ log = File.open(log_path, 'w')
50
+ FileStat.set_log(log)
51
+
52
+ while true do
53
+ # pull entry that should be checked next,
54
+ # according to it's scan_period
55
+ time, conf, dir_stat = pq.pop
56
+
57
+ # time remains to wait before directory should be checked
58
+ time_span = time - Time.now.to_i
59
+ if (time_span > 0)
60
+ sleep(time_span)
65
61
  end
62
+ dir_stat.monitor
66
63
 
67
- log.close
64
+ # push entry with new a next time it should be checked as a priority key
65
+ priority = (Time.now + conf['scan_period']).to_i
66
+ pq.push([priority, conf, dir_stat], -priority)
68
67
  end
69
- end
70
68
 
69
+ log.close
70
+ end
71
71
  end
72
+
72
73
  end
74
+
@@ -1,292 +1,291 @@
1
1
  require 'log'
2
2
  require 'params'
3
3
 
4
- module BBFS
5
- module FileMonitoring
6
- # Path monitoring.
7
-
8
- # Enum-like structure that includes possible filesystem entities (files/directories) states:
9
- # * <tt>NON_EXISTING</tt> - Entity that was treated during previous run, but absent currently
10
- # * <tt>NEW</tt> - Entity that was found and added to control during this run
11
- # * <tt>CHANGED</tt> - State was changed between two checks
12
- # * <tt>UNCHANGED</tt> - Opposite to CHANGED
13
- # * <tt>STABLE</tt> - Entity is in the UNCHANGED state for a defined (by user) number of iterations
14
- class FileStatEnum
15
- NON_EXISTING = "NON_EXISTING"
16
- NEW = "NEW"
17
- CHANGED = "CHANGED"
18
- UNCHANGED = "UNCHANGED"
19
- STABLE = "STABLE"
20
- end
4
+ module FileMonitoring
5
+ # Path monitoring.
6
+
7
+ # Enum-like structure that includes possible filesystem entities (files/directories) states:
8
+ # * <tt>NON_EXISTING</tt> - Entity that was treated during previous run, but absent currently
9
+ # * <tt>NEW</tt> - Entity that was found and added to control during this run
10
+ # * <tt>CHANGED</tt> - State was changed between two checks
11
+ # * <tt>UNCHANGED</tt> - Opposite to CHANGED
12
+ # * <tt>STABLE</tt> - Entity is in the UNCHANGED state for a defined (by user) number of iterations
13
+ class FileStatEnum
14
+ NON_EXISTING = "NON_EXISTING"
15
+ NEW = "NEW"
16
+ CHANGED = "CHANGED"
17
+ UNCHANGED = "UNCHANGED"
18
+ STABLE = "STABLE"
19
+ end
21
20
 
22
- # This class holds current state of file and methods to control and report changes
23
- class FileStat
24
- attr_reader :cycles, :path, :stable_state, :state, :size, :modification_time
21
+ # This class holds current state of file and methods to control and report changes
22
+ class FileStat
23
+ attr_reader :cycles, :path, :stable_state, :state, :size, :modification_time
25
24
 
26
- DEFAULT_STABLE_STATE = 10
25
+ DEFAULT_STABLE_STATE = 10
27
26
 
28
- @@log = nil
27
+ @@log = nil
29
28
 
30
- # Initializes new file monitoring object
31
- # ==== Arguments:
32
- #
33
- # * <tt>path</tt> - File location
34
- # * <tt>stable_state</tt> - Number of iterations to move unchanged file to stable state
35
- def initialize(path, stable_state = DEFAULT_STABLE_STATE)
36
- @path ||= path
37
- @size = nil
38
- @creation_time = nil
39
- @modification_time = nil
40
- @cycles = 0 # number of iterations from the last file modification
41
- @state = FileStatEnum::NON_EXISTING
29
+ # Initializes new file monitoring object
30
+ # ==== Arguments:
31
+ #
32
+ # * <tt>path</tt> - File location
33
+ # * <tt>stable_state</tt> - Number of iterations to move unchanged file to stable state
34
+ def initialize(path, stable_state = DEFAULT_STABLE_STATE)
35
+ @path ||= path
36
+ @size = nil
37
+ @creation_time = nil
38
+ @modification_time = nil
39
+ @cycles = 0 # number of iterations from the last file modification
40
+ @state = FileStatEnum::NON_EXISTING
42
41
 
43
- @stable_state = stable_state # number of iteration to move unchanged file to stable state
44
- end
42
+ @stable_state = stable_state # number of iteration to move unchanged file to stable state
43
+ end
45
44
 
46
- def set_output_queue(event_queue)
47
- @event_queue = event_queue
48
- end
45
+ def set_output_queue(event_queue)
46
+ @event_queue = event_queue
47
+ end
49
48
 
50
- # Sets a log file to report changes
51
- # ==== Arguments:
52
- #
53
- # * <tt>log</tt> - already opened ruby File object
54
- def self.set_log (log)
55
- @@log = log
56
- end
49
+ # Sets a log file to report changes
50
+ # ==== Arguments:
51
+ #
52
+ # * <tt>log</tt> - already opened ruby File object
53
+ def self.set_log (log)
54
+ @@log = log
55
+ end
57
56
 
58
- # Checks whether file was changed from the last iteration.
59
- # For files size and modification time are checked.
60
- def monitor
61
- file_stats = File.lstat(@path) rescue nil
62
- new_state = nil
63
- if file_stats == nil
64
- new_state = FileStatEnum::NON_EXISTING
65
- @size = nil
66
- @creation_time = nil
67
- @modification_time = nil
68
- @cycles = 0
69
- elsif @size == nil
70
- new_state = FileStatEnum::NEW
71
- @size = file_stats.size
72
- @creation_time = file_stats.ctime.utc
73
- @modification_time = file_stats.mtime.utc
74
- @cycles = 0
75
- elsif changed?(file_stats)
76
- new_state = FileStatEnum::CHANGED
77
- @size = file_stats.size
78
- @creation_time = file_stats.ctime.utc
79
- @modification_time = file_stats.mtime.utc
80
- @cycles = 0
81
- else
82
- new_state = FileStatEnum::UNCHANGED
83
- @cycles += 1
84
- if @cycles >= @stable_state
85
- new_state = FileStatEnum::STABLE
86
- end
57
+ # Checks whether file was changed from the last iteration.
58
+ # For files, size and modification time are checked.
59
+ def monitor
60
+ file_stats = File.lstat(@path) rescue nil
61
+ new_state = nil
62
+ if file_stats == nil
63
+ new_state = FileStatEnum::NON_EXISTING
64
+ @size = nil
65
+ @creation_time = nil
66
+ @modification_time = nil
67
+ @cycles = 0
68
+ elsif @size == nil
69
+ new_state = FileStatEnum::NEW
70
+ @size = file_stats.size
71
+ @creation_time = file_stats.ctime.utc
72
+ @modification_time = file_stats.mtime.utc
73
+ @cycles = 0
74
+ elsif changed?(file_stats)
75
+ new_state = FileStatEnum::CHANGED
76
+ @size = file_stats.size
77
+ @creation_time = file_stats.ctime.utc
78
+ @modification_time = file_stats.mtime.utc
79
+ @cycles = 0
80
+ else
81
+ new_state = FileStatEnum::UNCHANGED
82
+ @cycles += 1
83
+ if @cycles >= @stable_state
84
+ new_state = FileStatEnum::STABLE
87
85
  end
88
-
89
- # The assignment
90
- self.state= new_state
91
86
  end
92
87
 
93
- # Checks that stored file attributes are the same as file attributes taken from file system.
94
- def changed?(file_stats)
95
- not (file_stats.size == @size &&
96
- file_stats.ctime.utc == @creation_time.utc &&
97
- file_stats.mtime.utc == @modification_time.utc)
98
- end
88
+ # The assignment
89
+ self.state= new_state
90
+ end
99
91
 
100
- def set_event_queue(queue)
101
- @event_queue = queue
102
- end
92
+ # Checks that stored file attributes are the same as file attributes taken from file system.
93
+ def changed?(file_stats)
94
+ not (file_stats.size == @size &&
95
+ file_stats.ctime.utc == @creation_time.utc &&
96
+ file_stats.mtime.utc == @modification_time.utc)
97
+ end
103
98
 
104
- # Sets and writes to the log a new state.
105
- def state= (new_state)
106
- if (@state != new_state or @state == FileStatEnum::CHANGED)
107
- @state = new_state
108
- if (@@log)
109
- @@log.puts(cur_stat)
110
- @@log.flush #Ruby1.9.3: note that this is Ruby internal buffering only; the OS may buffer the data as well
111
- end
112
- if (!@event_queue.nil?)
113
- Log.info "Writing to event queue [#{self.state}, #{self.path}]"
114
- @event_queue.push([self.state, self.instance_of?(DirStat), self.path])
115
- end
99
+ def set_event_queue(queue)
100
+ @event_queue = queue
101
+ end
102
+
103
+ # Sets and writes to the log a new state.
104
+ def state= (new_state)
105
+ if (@state != new_state or @state == FileStatEnum::CHANGED)
106
+ @state = new_state
107
+ if (@@log)
108
+ @@log.puts(cur_stat)
109
+ @@log.flush #Ruby1.9.3: note that this is Ruby internal buffering only; the OS may buffer the data as well
110
+ end
111
+ if (!@event_queue.nil?)
112
+ Log.info "Writing to event queue [#{self.state}, #{self.path}]"
113
+ @event_queue.push([self.state, self.instance_of?(DirStat), self.path])
116
114
  end
117
115
  end
116
+ end
118
117
 
119
- # Checks whether path and state are the same as of the argument
120
- def == (other)
121
- @path == other.path and @stable_state == other.stable_state
122
- end
118
+ # Checks whether path and state are the same as of the argument
119
+ def == (other)
120
+ @path == other.path and @stable_state == other.stable_state
121
+ end
123
122
 
124
- # Returns path and state of the file with indentation
125
- def to_s (indent = 0)
126
- (" " * indent) + path.to_s + " : " + state.to_s
127
- end
123
+ # Returns path and state of the file with indentation
124
+ def to_s (indent = 0)
125
+ (" " * indent) + path.to_s + " : " + state.to_s
126
+ end
128
127
 
129
- # Reports current state with identification.
130
- # # This format used by log file.
131
- def cur_stat
132
- # TODO what output format have to be ?
133
- Time.now.utc.to_s + " : " + self.state + " : " + self.path
134
- end
128
+ # Reports current state with identification.
129
+ # NOTE This format used by log file.
130
+ def cur_stat
131
+ # TODO what output format have to be ?
132
+ Time.now.utc.to_s + " : " + self.state + " : " + self.path
135
133
  end
134
+ end
136
135
 
137
- # This class holds current state of directory and methods to control changes
138
- class DirStat < FileStat
139
- # Initializes new directory monitoring object
140
- # ==== Arguments:
141
- #
142
- # * <tt>path</tt> - File location
143
- # * <tt>stable_state</tt> - Number of iterations to move unchanged directory to stable state
144
- def initialize(path, stable_state = DEFAULT_STABLE_STATE)
145
- super
146
- @dirs = nil
147
- @files = nil
148
- end
136
+ # This class holds current state of directory and methods to control changes
137
+ class DirStat < FileStat
138
+ # Initializes new directory monitoring object
139
+ # ==== Arguments:
140
+ #
141
+ # * <tt>path</tt> - File location
142
+ # * <tt>stable_state</tt> - Number of iterations to move unchanged directory to stable state
143
+ def initialize(path, stable_state = DEFAULT_STABLE_STATE)
144
+ super
145
+ @dirs = nil
146
+ @files = nil
147
+ end
149
148
 
150
- # Adds directory for monitoring.
151
- def add_dir (dir)
152
- @dirs[dir.path] = dir
153
- end
149
+ # Adds directory for monitoring.
150
+ def add_dir (dir)
151
+ @dirs[dir.path] = dir
152
+ end
154
153
 
155
- # Adds file for monitoring.
156
- def add_file (file)
157
- @files[file.path] = file
158
- end
154
+ # Adds file for monitoring.
155
+ def add_file (file)
156
+ @files[file.path] = file
157
+ end
159
158
 
160
- # Removes directory from monitoring.
161
- def rm_dir(dir)
162
- @dirs.delete(dir.path)
163
- end
159
+ # Removes directory from monitoring.
160
+ def rm_dir(dir)
161
+ @dirs.delete(dir.path)
162
+ end
164
163
 
165
- # Removes file from monitoring.
166
- def rm_file(file)
167
- @files.delete(file.path)
168
- end
164
+ # Removes file from monitoring.
165
+ def rm_file(file)
166
+ @files.delete(file.path)
167
+ end
169
168
 
170
- # Checks that there is a sub-folder with a given path.
171
- def has_dir?(path)
172
- @dirs.has_key?(path)
173
- end
169
+ # Checks that there is a sub-folder with a given path.
170
+ def has_dir?(path)
171
+ @dirs.has_key?(path)
172
+ end
174
173
 
175
- # Checks that there is a file with a given path.
176
- def has_file?(path)
177
- @files.has_key?(path)
178
- end
174
+ # Checks that there is a file with a given path.
175
+ def has_file?(path)
176
+ @files.has_key?(path)
177
+ end
179
178
 
180
- # Returns string with contains path and state of this directory as well as it's structure.
181
- def to_s(indent = 0)
182
- indent_increment = 2
183
- child_indent = indent + indent_increment
184
- res = super
185
- @files.each_value do |file|
186
- res += "\n" + file.to_s(child_ident)
187
- end if @files
188
- @dirs.each_value do |dir|
189
- res += "\n" + dir.to_s(child_ident)
190
- end if @dirs
191
- res
192
- end
179
+ # Returns string which contains path and state of this directory as well as it's structure.
180
+ def to_s(indent = 0)
181
+ indent_increment = 2
182
+ child_indent = indent + indent_increment
183
+ res = super
184
+ @files.each_value do |file|
185
+ res += "\n" + file.to_s(child_ident)
186
+ end if @files
187
+ @dirs.each_value do |dir|
188
+ res += "\n" + dir.to_s(child_ident)
189
+ end if @dirs
190
+ res
191
+ end
193
192
 
194
- # Checks that directory structure (i.e. files and directories located directly under this directory)
195
- # wasn't changed since the last iteration.
196
- def monitor
197
- was_changed = false
198
- new_state = nil
199
- self_stat = File.lstat(@path) rescue nil
200
- if self_stat == nil
201
- new_state = FileStatEnum::NON_EXISTING
202
- @files = nil
203
- @dirs = nil
204
- @cycles = 0
205
- elsif @files == nil
206
- new_state = FileStatEnum::NEW
207
- @files = Hash.new
208
- @dirs = Hash.new
209
- @cycles = 0
210
- update_dir
211
- elsif update_dir
212
- new_state = FileStatEnum::CHANGED
213
- @cycles = 0
214
- else
215
- new_state = FileStatEnum::UNCHANGED
216
- @cycles += 1
217
- if @cycles >= @stable_state
218
- new_state = FileStatEnum::STABLE
219
- end
193
+ # Checks that directory structure (i.e. files and directories located directly under this directory)
194
+ # wasn't changed since the last iteration.
195
+ def monitor
196
+ was_changed = false
197
+ new_state = nil
198
+ self_stat = File.lstat(@path) rescue nil
199
+ if self_stat == nil
200
+ new_state = FileStatEnum::NON_EXISTING
201
+ @files = nil
202
+ @dirs = nil
203
+ @cycles = 0
204
+ elsif @files == nil
205
+ new_state = FileStatEnum::NEW
206
+ @files = Hash.new
207
+ @dirs = Hash.new
208
+ @cycles = 0
209
+ update_dir
210
+ elsif update_dir
211
+ new_state = FileStatEnum::CHANGED
212
+ @cycles = 0
213
+ else
214
+ new_state = FileStatEnum::UNCHANGED
215
+ @cycles += 1
216
+ if @cycles >= @stable_state
217
+ new_state = FileStatEnum::STABLE
220
218
  end
221
-
222
- # The assignment
223
- self.state= new_state
224
219
  end
225
220
 
226
- # Updates the files and directories hashes and globs the directory for changes.
227
- def update_dir
228
- was_changed = false
221
+ # The assignment
222
+ self.state= new_state
223
+ end
229
224
 
230
- # monitor existing and absent files
231
- @files.each_value do |file|
232
- file.monitor
225
+ # Updates the files and directories hashes and globs the directory for changes.
226
+ def update_dir
227
+ was_changed = false
233
228
 
234
- if file.state == FileStatEnum::NON_EXISTING
235
- was_changed = true
236
- rm_file(file)
237
- end
229
+ # monitor existing and absent files
230
+ @files.each_value do |file|
231
+ file.monitor
232
+
233
+ if file.state == FileStatEnum::NON_EXISTING
234
+ was_changed = true
235
+ rm_file(file)
238
236
  end
237
+ end
239
238
 
240
- @dirs.each_value do |dir|
241
- dir.monitor
239
+ @dirs.each_value do |dir|
240
+ dir.monitor
242
241
 
243
- if dir.state == FileStatEnum::NON_EXISTING
244
- was_changed = true
245
- rm_dir(dir)
246
- end
242
+ if dir.state == FileStatEnum::NON_EXISTING
243
+ was_changed = true
244
+ rm_dir(dir)
247
245
  end
246
+ end
248
247
 
249
- was_changed = was_changed || glob_me
248
+ was_changed = was_changed || glob_me
250
249
 
251
- return was_changed
252
- end
250
+ return was_changed
251
+ end
253
252
 
254
- # Globs the directory for new files and directories
255
- def glob_me
256
- was_changed = false
257
- files = Dir.glob(path + "/*")
258
-
259
- # add and monitor new files and directories
260
- files.each do |file|
261
- file_stat = File.lstat(file) rescue nil
262
- if (file_stat.directory?)
263
- unless (has_dir?(file)) # new directory
264
- # change state only for existing directories
265
- # newly added directories have to remain with NEW state
266
- was_changed = true
267
- ds = DirStat.new(file, self.stable_state)
268
- ds.set_event_queue(@event_queue) unless @event_queue.nil?
269
- ds.monitor
270
- add_dir(ds)
271
- end
272
- else # it is a file
273
- unless(has_file?(file)) # new file
274
- # change state only for existing directories
275
- # newly added directories have to remain with NEW state
276
- was_changed = true
277
- fs = FileStat.new(file, self.stable_state)
278
- fs.set_event_queue(@event_queue) unless @event_queue.nil?
279
- fs.monitor
280
- add_file(fs)
281
- end
253
+ # Globs the directory for new files and directories
254
+ def glob_me
255
+ was_changed = false
256
+ files = Dir.glob(path + "/*")
257
+
258
+ # add and monitor new files and directories
259
+ files.each do |file|
260
+ file_stat = File.lstat(file) rescue nil
261
+ if (file_stat.directory?)
262
+ unless (has_dir?(file)) # new directory
263
+ # change state only for existing directories
264
+ # newly added directories have to remain with NEW state
265
+ was_changed = true
266
+ ds = DirStat.new(file, self.stable_state)
267
+ ds.set_event_queue(@event_queue) unless @event_queue.nil?
268
+ ds.monitor
269
+ add_dir(ds)
270
+ end
271
+ else # it is a file
272
+ unless(has_file?(file)) # new file
273
+ # change state only for existing directories
274
+ # newly added directories have to remain with NEW state
275
+ was_changed = true
276
+ fs = FileStat.new(file, self.stable_state)
277
+ fs.set_event_queue(@event_queue) unless @event_queue.nil?
278
+ fs.monitor
279
+ add_file(fs)
282
280
  end
283
281
  end
284
-
285
- return was_changed
286
282
  end
287
283
 
288
- protected :add_dir, :add_file, :rm_dir, :rm_file, :update_dir, :glob_me
284
+ return was_changed
289
285
  end
290
286
 
287
+ protected :add_dir, :add_file, :rm_dir, :rm_file, :update_dir, :glob_me
291
288
  end
289
+
292
290
  end
291
+
@@ -1,5 +1,3 @@
1
- module BBFS
2
- module FileMonitoring
3
- VERSION = "0.0.9"
4
- end
1
+ module FileMonitoring
2
+ VERSION = "1.0.0"
5
3
  end
@@ -2,156 +2,152 @@ require './lib/file_monitoring/monitor_path'
2
2
  require 'test/unit'
3
3
  require 'fileutils'
4
4
 
5
- module BBFS
6
- module FileMonitoring
7
- module Test
8
- class TestPathMonitor < ::Test::Unit::TestCase
9
- # directory where tested files will be placed: __FILE__/time_modification_test
10
- RESOURCES_DIR = File.expand_path(File.dirname(__FILE__) + '/path_monitor_test')
11
- MOVE_DIR = '/dir1500' # directory that will be moved
12
- MOVE_FILE = '/test_file.1000' # file that will be moved
13
- MOVE_SRC_DIR = RESOURCES_DIR + '/dir1000' # directory where moved entities where placed
14
- MOVE_DEST_DIR = RESOURCES_DIR # directory where moved entities will be placed
15
- LOG_PATH = RESOURCES_DIR + '/../log.txt'
16
-
17
- def setup
18
- @sizes = [500, 1000, 1500]
19
- @numb_of_copies = 2
20
- @numb_entities = @sizes.size * (@numb_of_copies + 1) + @sizes.size
21
- @test_file_name = 'test_file' # file name format: <test_file_name_prefix>.<size>[.serial_number_if_more_then_1]
22
- @test_dir_name = 'dir'
23
- ::FileUtils.rm_rf(RESOURCES_DIR) if (File.exists?(RESOURCES_DIR))
24
-
25
- # prepare files for testing
26
- cur_dir = nil; # directory where currently files created in this iteration will be placed
27
-
28
- @sizes.each do |size|
29
- file_name = @test_file_name + '.' + size.to_s
30
-
31
- if (cur_dir == nil)
32
- cur_dir = String.new(RESOURCES_DIR)
33
- else
34
- cur_dir = cur_dir + "/#{@test_dir_name}" + size.to_s
35
- end
36
- Dir.mkdir(cur_dir) unless (File.exists?(cur_dir))
37
- raise "Can't create writable working directory: #{cur_dir}" unless (File.exists?(cur_dir) and File.writable?(cur_dir))
38
-
39
- file_path = cur_dir + '/' + file_name
40
- File.open(file_path, 'w') do |file|
41
- content = Array.new
42
- size.times do |i|
43
- content.push(sprintf('%5d ', i))
44
- end
45
- file.puts(content)
46
- end
47
-
48
- @numb_of_copies.times do |i|
49
- ::FileUtils.cp(file_path, "#{file_path}.#{i}")
5
+ module FileMonitoring
6
+ module Test
7
+ class TestPathMonitor < ::Test::Unit::TestCase
8
+ # directory where tested files will be placed: __FILE__/time_modification_test
9
+ RESOURCES_DIR = File.expand_path(File.dirname(__FILE__) + '/path_monitor_test')
10
+ MOVE_DIR = '/dir1500' # directory that will be moved
11
+ MOVE_FILE = '/test_file.1000' # file that will be moved
12
+ MOVE_SRC_DIR = RESOURCES_DIR + '/dir1000' # directory where moved entities where placed
13
+ MOVE_DEST_DIR = RESOURCES_DIR # directory where moved entities will be placed
14
+ LOG_PATH = RESOURCES_DIR + '/../log.txt'
15
+
16
+ def setup
17
+ @sizes = [500, 1000, 1500]
18
+ @numb_of_copies = 2
19
+ @numb_entities = @sizes.size * (@numb_of_copies + 1) + @sizes.size
20
+ @test_file_name = 'test_file' # file name format: <test_file_name_prefix>.<size>[.serial_number_if_more_then_1]
21
+ @test_dir_name = 'dir'
22
+ ::FileUtils.rm_rf(RESOURCES_DIR) if (File.exists?(RESOURCES_DIR))
23
+
24
+ # prepare files for testing
25
+ cur_dir = nil; # directory where currently files created in this iteration will be placed
26
+
27
+ @sizes.each do |size|
28
+ file_name = @test_file_name + '.' + size.to_s
29
+
30
+ if (cur_dir == nil)
31
+ cur_dir = String.new(RESOURCES_DIR)
32
+ else
33
+ cur_dir = cur_dir + "/#{@test_dir_name}" + size.to_s
34
+ end
35
+ Dir.mkdir(cur_dir) unless (File.exists?(cur_dir))
36
+ raise "Can't create writable working directory: #{cur_dir}" unless (File.exists?(cur_dir) and File.writable?(cur_dir))
37
+
38
+ file_path = cur_dir + '/' + file_name
39
+ File.open(file_path, 'w') do |file|
40
+ content = Array.new
41
+ size.times do |i|
42
+ content.push(sprintf('%5d ', i))
50
43
  end
44
+ file.puts(content)
51
45
  end
52
- end
53
-
54
- def test_monitor
55
- log = File.open(LOG_PATH, 'w+')
56
- FileStat.set_log(log)
57
- test_dir = DirStat.new(RESOURCES_DIR)
58
-
59
- # Initial run of monitoring -> initializing DirStat object
60
- # all found object will be set to NEW state
61
- # no output to the log
62
- test_dir.monitor
63
46
 
64
- # all files will be set to UNCHANGED
65
- log_prev_pos = log.pos
66
- log_prev_line = log.lineno
67
- test_dir.monitor
68
- sleep(1) # to be sure that data was indeed written
69
- log.pos= log_prev_pos
70
- log.each_line do |line|
71
- assert_equal(true, line.include?(FileStatEnum::UNCHANGED))
47
+ @numb_of_copies.times do |i|
48
+ ::FileUtils.cp(file_path, "#{file_path}.#{i}")
72
49
  end
73
- assert_equal(@numb_entities, log.lineno - log_prev_line) # checking that all entities were monitored
50
+ end
51
+ end
74
52
 
75
- # move (equivalent to delete and create new) directory with including files to new location
76
- ::FileUtils.mv MOVE_SRC_DIR + MOVE_DIR, MOVE_DEST_DIR + MOVE_DIR
77
- log_prev_pos = log.pos
78
- log_prev_line = log.lineno
79
- test_dir.monitor
80
- sleep(1)
81
- log.pos= log_prev_pos
82
- log.each_line do |line|
83
- if (line.include?(MOVE_SRC_DIR + MOVE_DIR))
84
- assert_equal(true, line.include?(FileStatEnum::NON_EXISTING))
85
- elsif (line.include?(MOVE_DEST_DIR + MOVE_DIR))
86
- assert_equal(true, line.include?(FileStatEnum::NEW))
87
- elsif (line.include?(MOVE_SRC_DIR) or line.include?(MOVE_DEST_DIR))
88
- assert_not_equal(true, line.include?(FileStatEnum::UNCHANGED))
89
- assert_equal(true, line.include?(FileStatEnum::CHANGED))
90
- end
91
- end
92
- # old and new containing directories: 2
93
- # moved directory: 1
94
- # deleted directory: 1
95
- # moved files: @numb_of_copies + 1
96
- assert_equal(5 + @numb_of_copies, log.lineno - log_prev_line) # checking that only MOVE_DIR_SRC, MOVE_DIR_DEST states were changed
97
-
98
- # no changes:
99
- # changed and new files moved to UNCHANGED
100
- log_prev_pos = log.pos
101
- log_prev_line = log.lineno
102
- test_dir.monitor
103
- sleep(1)
104
- log.pos= log_prev_pos
105
- log.each_line do |line|
106
- assert_equal(true, line.include?(FileStatEnum::UNCHANGED))
53
+ def test_monitor
54
+ log = File.open(LOG_PATH, 'w+')
55
+ FileStat.set_log(log)
56
+ test_dir = DirStat.new(RESOURCES_DIR)
57
+
58
+ # Initial run of monitoring -> initializing DirStat object
59
+ # all found object will be set to NEW state
60
+ # no output to the log
61
+ test_dir.monitor
62
+
63
+ # all files will be set to UNCHANGED
64
+ log_prev_pos = log.pos
65
+ log_prev_line = log.lineno
66
+ test_dir.monitor
67
+ sleep(1) # to be sure that data was indeed written
68
+ log.pos= log_prev_pos
69
+ log.each_line do |line|
70
+ assert_equal(true, line.include?(FileStatEnum::UNCHANGED))
71
+ end
72
+ assert_equal(@numb_entities, log.lineno - log_prev_line) # checking that all entities were monitored
73
+
74
+ # move (equivalent to delete and create new) directory with including files to new location
75
+ ::FileUtils.mv MOVE_SRC_DIR + MOVE_DIR, MOVE_DEST_DIR + MOVE_DIR
76
+ log_prev_pos = log.pos
77
+ log_prev_line = log.lineno
78
+ test_dir.monitor
79
+ sleep(1)
80
+ log.pos= log_prev_pos
81
+ log.each_line do |line|
82
+ if (line.include?(MOVE_SRC_DIR + MOVE_DIR))
83
+ assert_equal(true, line.include?(FileStatEnum::NON_EXISTING))
84
+ elsif (line.include?(MOVE_DEST_DIR + MOVE_DIR))
85
+ assert_equal(true, line.include?(FileStatEnum::NEW))
86
+ elsif (line.include?(MOVE_SRC_DIR) or line.include?(MOVE_DEST_DIR))
87
+ assert_not_equal(true, line.include?(FileStatEnum::UNCHANGED))
88
+ assert_equal(true, line.include?(FileStatEnum::CHANGED))
107
89
  end
108
- # old and new containing directories: 2
109
- # moved directory: 1
110
- # moved files: @numb_of_copies + 1
111
- assert_equal(4 + @numb_of_copies, log.lineno - log_prev_line)
112
-
113
- # move (equivalent to delete and create new) file
114
- log_prev_pos = log.pos
115
- log_prev_line = log.lineno
116
- ::FileUtils.mv MOVE_SRC_DIR + MOVE_FILE, MOVE_DEST_DIR + MOVE_FILE
117
- test_dir.monitor
118
- sleep(1)
119
- log.pos= log_prev_pos
120
- log.each_line do |line|
121
- if (line.include?MOVE_SRC_DIR + MOVE_FILE)
122
- assert_equal(true, line.include?(FileStatEnum::NON_EXISTING))
123
- elsif (line.include?MOVE_DEST_DIR + MOVE_FILE)
124
- assert_equal(true, line.include?(FileStatEnum::NEW))
125
- elsif (line.include?MOVE_SRC_DIR or line.include?MOVE_DEST_DIR)
126
- assert_equal(true, line.include?(FileStatEnum::CHANGED))
127
- end
90
+ end
91
+ # old and new containing directories: 2
92
+ # moved directory: 1
93
+ # deleted directory: 1
94
+ # moved files: @numb_of_copies + 1
95
+ assert_equal(5 + @numb_of_copies, log.lineno - log_prev_line) # checking that only MOVE_DIR_SRC, MOVE_DIR_DEST states were changed
96
+
97
+ # no changes:
98
+ # changed and new files moved to UNCHANGED
99
+ log_prev_pos = log.pos
100
+ log_prev_line = log.lineno
101
+ test_dir.monitor
102
+ sleep(1)
103
+ log.pos= log_prev_pos
104
+ log.each_line do |line|
105
+ assert_equal(true, line.include?(FileStatEnum::UNCHANGED))
106
+ end
107
+ # old and new containing directories: 2
108
+ # moved directory: 1
109
+ # moved files: @numb_of_copies + 1
110
+ assert_equal(4 + @numb_of_copies, log.lineno - log_prev_line)
111
+
112
+ # move (equivalent to delete and create new) file
113
+ log_prev_pos = log.pos
114
+ log_prev_line = log.lineno
115
+ ::FileUtils.mv MOVE_SRC_DIR + MOVE_FILE, MOVE_DEST_DIR + MOVE_FILE
116
+ test_dir.monitor
117
+ sleep(1)
118
+ log.pos= log_prev_pos
119
+ log.each_line do |line|
120
+ if (line.include?MOVE_SRC_DIR + MOVE_FILE)
121
+ assert_equal(true, line.include?(FileStatEnum::NON_EXISTING))
122
+ elsif (line.include?MOVE_DEST_DIR + MOVE_FILE)
123
+ assert_equal(true, line.include?(FileStatEnum::NEW))
124
+ elsif (line.include?MOVE_SRC_DIR or line.include?MOVE_DEST_DIR)
125
+ assert_equal(true, line.include?(FileStatEnum::CHANGED))
128
126
  end
129
- # old and new containing directories: 2
130
- # removed file: 1
131
- # new file: 1
132
- assert_equal(4, log.lineno - log_prev_line)
133
-
134
- # all files were moved to UNCHANGED
127
+ end
128
+ # old and new containing directories: 2
129
+ # removed file: 1
130
+ # new file: 1
131
+ assert_equal(4, log.lineno - log_prev_line)
132
+
133
+ # all files were moved to UNCHANGED
134
+ test_dir.monitor
135
+
136
+ # check that all entities moved to stable
137
+ log_prev_pos = log.pos
138
+ log_prev_line = log.lineno
139
+ (test_dir.stable_state + 1).times do
135
140
  test_dir.monitor
136
-
137
- # check that all entities moved to stable
138
- log_prev_pos = log.pos
139
- log_prev_line = log.lineno
140
- (test_dir.stable_state + 1).times do
141
- test_dir.monitor
142
- end
143
- sleep(1)
144
- log.pos= log_prev_pos
145
- log.each_line do |line|
146
- assert_equal(true, line.include?(FileStatEnum::STABLE))
147
- end
148
- assert_equal(@numb_entities, log.lineno - log_prev_line)
149
-
150
- log.close
151
141
  end
152
- end
153
-
142
+ sleep(1)
143
+ log.pos= log_prev_pos
144
+ log.each_line do |line|
145
+ assert_equal(true, line.include?(FileStatEnum::STABLE))
146
+ end
147
+ assert_equal(@numb_entities, log.lineno - log_prev_line)
154
148
 
149
+ log.close
150
+ end
155
151
  end
156
152
  end
157
153
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: file_monitoring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -76,33 +76,32 @@ dependencies:
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  description: Deamon for monitoring file changes in set of patterns (blobs).
79
- email: kolmanv@gmail.com
79
+ email: bbfsdev@gmail.com
80
80
  executables:
81
81
  - file_monitoring
82
82
  extensions: []
83
83
  extra_rdoc_files: []
84
84
  files:
85
85
  - lib/file_monitoring.rb
86
- - lib/file_monitoring/daemon_win32.rb
87
- - lib/file_monitoring/file_monitoring.rb
88
86
  - lib/file_monitoring/monitor_path.rb
89
87
  - lib/file_monitoring/version.rb
88
+ - lib/file_monitoring/file_monitoring.rb
90
89
  - test/file_monitoring/file_monitoring_test/conf.yml
91
- - test/file_monitoring/file_monitoring_test/conf_win32.yml
92
90
  - test/file_monitoring/file_monitoring_test/log
93
- - test/file_monitoring/file_monitoring_test.rb
94
- - test/file_monitoring/monitor_path_test/dir1000/test_file.1000
95
- - test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0
91
+ - test/file_monitoring/file_monitoring_test/conf_win32.yml
92
+ - test/file_monitoring/monitor_path_test/test_file.500.0
96
93
  - test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1
94
+ - test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0
95
+ - test/file_monitoring/monitor_path_test/dir1000/test_file.1000
96
+ - test/file_monitoring/monitor_path_test/test_file.500.1
97
+ - test/file_monitoring/monitor_path_test/test_file.500
97
98
  - test/file_monitoring/monitor_path_test/dir1500/test_file.1500
98
99
  - test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0
99
100
  - test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1
100
- - test/file_monitoring/monitor_path_test/test_file.500
101
- - test/file_monitoring/monitor_path_test/test_file.500.0
102
- - test/file_monitoring/monitor_path_test/test_file.500.1
101
+ - test/file_monitoring/file_monitoring_test.rb
103
102
  - test/file_monitoring/monitor_path_test.rb
104
103
  - bin/file_monitoring
105
- homepage: http://github.com/kolmanv/bbfs
104
+ homepage: http://github.com/bbfsdev/bbfs
106
105
  licenses: []
107
106
  post_install_message:
108
107
  rdoc_options: []
@@ -128,16 +127,16 @@ specification_version: 3
128
127
  summary: Deamon for monitoring file changes.
129
128
  test_files:
130
129
  - test/file_monitoring/file_monitoring_test/conf.yml
131
- - test/file_monitoring/file_monitoring_test/conf_win32.yml
132
130
  - test/file_monitoring/file_monitoring_test/log
133
- - test/file_monitoring/file_monitoring_test.rb
134
- - test/file_monitoring/monitor_path_test/dir1000/test_file.1000
135
- - test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0
131
+ - test/file_monitoring/file_monitoring_test/conf_win32.yml
132
+ - test/file_monitoring/monitor_path_test/test_file.500.0
136
133
  - test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1
134
+ - test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0
135
+ - test/file_monitoring/monitor_path_test/dir1000/test_file.1000
136
+ - test/file_monitoring/monitor_path_test/test_file.500.1
137
+ - test/file_monitoring/monitor_path_test/test_file.500
137
138
  - test/file_monitoring/monitor_path_test/dir1500/test_file.1500
138
139
  - test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0
139
140
  - test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1
140
- - test/file_monitoring/monitor_path_test/test_file.500
141
- - test/file_monitoring/monitor_path_test/test_file.500.0
142
- - test/file_monitoring/monitor_path_test/test_file.500.1
141
+ - test/file_monitoring/file_monitoring_test.rb
143
142
  - test/file_monitoring/monitor_path_test.rb
@@ -1,29 +0,0 @@
1
- require 'win32/daemon'
2
- include Win32
3
- require 'rubygems'
4
-
5
- begin
6
- require "./file_monitoring/file_monitoring.rb"
7
-
8
- conf_file_path = (ARGV.length > 0 ? "#{ARGV[0]}" : '~/.bbfs/etc/file_monitoring.yml')
9
- conf_file_path = File.expand_path(conf_file_path)
10
-
11
- CONFIG_FILE_PATH = "#{conf_file_path}"
12
-
13
- class Daemon
14
- def service_main
15
- while running?
16
- monitor_files(CONFIG_FILE_PATH)
17
- end
18
- end
19
-
20
- def service_stop
21
- exit!
22
- end
23
- end
24
-
25
- Daemon.mainloop
26
-
27
- rescue Exception => err
28
- raise
29
- end