file_monitoring 0.0.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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