File: file_change_detector.rb

package info (click to toggle)
ruby-rgen 0.10.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,428 kB
  • sloc: ruby: 11,344; xml: 1,368; yacc: 72; makefile: 10
file content (84 lines) | stat: -rw-r--r-- 2,413 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
require 'digest'

module RGen

module Util

# The FileChangeDetector detects changes in a set of files.
# Changes are detected between successive calls to check_files with a give set of files.
# Changes include files being added, removed or having changed their content.
#
class FileChangeDetector

  FileInfo = Struct.new(:timestamp, :digest)

  # Create a FileChangeDetector, options include:
  #
  #  :file_added
  #    a proc which is called when a file is added, receives the filename
  #
  #  :file_removed
  #    a proc which is called when a file is removed, receives the filename
  #
  #  :file_changed
  #    a proc which is called when a file is changed, receives the filename
  #
  def initialize(options={})
    @file_added = options[:file_added]
    @file_removed = options[:file_removed]
    @file_changed = options[:file_changed]
    @file_info = {}
  end

  # Checks if any of the files has changed compared to the last call of check_files.
  # When called for the first time on a new object, all files will be reported as being added.
  # 
  def check_files(files)
    files_before = @file_info.keys
    used_files = {} 
    files.each do |file|
      begin
        if @file_info[file]
          if @file_info[file].timestamp != File.mtime(file)
            @file_info[file].timestamp = File.mtime(file)
            digest = calc_digest(file)
            if @file_info[file].digest != digest
              @file_info[file].digest = digest 
              @file_changed && @file_changed.call(file)
            end
          end
        else
          @file_info[file] = FileInfo.new
          @file_info[file].timestamp = File.mtime(file)
          @file_info[file].digest = calc_digest(file)
          @file_added && @file_added.call(file)
        end
        used_files[file] = true
      # protect against missing files
      rescue Errno::ENOENT
        # used_files is not set and @file_info will be removed below
        # notification hook hasn't been called yet since it comes after file accesses
      end
    end
    files_before.each do |file|
      if !used_files[file]
        @file_info.delete(file)
        @file_removed && @file_removed.call(file)
      end
    end
  end

  private

  def calc_digest(file)
    sha1 = Digest::SHA1.new
    sha1.file(file)
    sha1.hexdigest
  end

end

end

end