3 # This script watches modifications on the given directory, using the new # FSEvents API in Leopard.
5 require 'osx/foundation'
6 OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
12 $COMMAND = File.basename($0)
13 $USAGE = "Usage: #{$COMMAND} [OPTIONS] <command> [<args> ...]"
19 def run_command(*args)
23 rescue SystemCallError => e
34 def wait_until_interrupt
36 $stderr.puts "Press Control-C to stop monitoring"
37 sleep(1.0) while (true)
43 options = OpenStruct.new
44 options.directoriesOnly = false
45 options.outputFile = "-"
48 opts = OptionParser.new do |opts|
51 opts.separator "Specific options:"
53 opts.on("-d", "--dir-only", "Only display directories") do
54 options.directoriesOnly = true
57 opts.on("-o", "--output FILE", "Write output to a file") do |fileName|
58 options.outputFile = fileName
61 opts.on("-w", "--wait", "Wait until interrupted") do
65 opts.on_tail("-h", "--help", "Show this message") do
72 if !options.wait and ARGV == 0
76 if options.outputFile == "-"
77 outputHandle = $stdout.clone
79 outputHandle = File.open(options.outputFile, "w")
84 startId = FSEventsGetCurrentEventId()
85 # Used to compare with mtime, which only has second accuracy
86 startTime = Time.now.to_i
92 returnCode = run_command(*ARGV)
97 fsevents_cb = proc do |stream, ctx, numEvents, paths, marks, eventIDs|
99 numEvents.times do |n|
100 allPaths.add(paths[n])
104 stream = FSEventStreamCreate(
111 KFSEventStreamCreateFlagNoDefer)
113 die "Failed to create the FSEventStream" unless stream
115 FSEventStreamScheduleWithRunLoop(
117 CFRunLoopGetCurrent(),
118 KCFRunLoopDefaultMode)
120 ok = FSEventStreamStart(stream)
121 die "Failed to start the FSEventStream" unless ok
123 FSEventStreamFlushSync(stream)
124 allPaths.sort.each do |path|
125 if File.exists?(path)
126 outputHandle.puts path
127 if (!options.directoriesOnly)
128 Dir.foreach(path) do |file|
129 fullPath = File.join(path, file)
130 stat = File.stat(fullPath)
131 if (stat.mtime.to_i >= startTime)
132 outputHandle.puts " #{file}"
137 outputHandle.puts "#{path} !"
141 FSEventStreamStop(stream)
142 FSEventStreamInvalidate(stream)
143 FSEventStreamRelease(stream)