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 options = OpenStruct.new
20 options.directoriesOnly = false
21 options.outputFile = "-"
23 opts = OptionParser.new do |opts|
26 opts.separator "Specific options:"
28 opts.on("-d", "--dir-only", "Only display directories") do
29 options.directoriesOnly = true
32 opts.on("-o", "--output FILE", "Write output to a file") do |fileName|
33 options.outputFile = fileName
36 opts.on_tail("-h", "--help", "Show this message") do
43 die $USAGE unless ARGV.size >= 1
45 if options.outputFile == "-"
46 outputHandle = $stdout.clone
48 outputHandle = File.open(options.outputFile, "w")
53 startId = FSEventsGetCurrentEventId()
54 # Used to compare with mtime, which only has second accuracy
55 startTime = Time.now.to_i
60 rescue SystemCallError => e
72 fsevents_cb = proc do |stream, ctx, numEvents, paths, marks, eventIDs|
74 numEvents.times do |n|
75 allPaths.add(paths[n])
79 stream = FSEventStreamCreate(
86 KFSEventStreamCreateFlagNoDefer)
88 die "Failed to create the FSEventStream" unless stream
90 FSEventStreamScheduleWithRunLoop(
92 CFRunLoopGetCurrent(),
93 KCFRunLoopDefaultMode)
95 ok = FSEventStreamStart(stream)
96 die "Failed to start the FSEventStream" unless ok
98 FSEventStreamFlushSync(stream)
99 allPaths.sort.each do |path|
100 if File.exists?(path)
101 outputHandle.puts path
102 if (!options.directoriesOnly)
103 Dir.foreach(path) do |file|
104 fullPath = File.join(path, file)
105 stat = File.stat(fullPath)
106 if (stat.mtime.to_i >= startTime)
107 outputHandle.puts " #{file}"
112 outputHandle.puts "#{path} !"
116 FSEventStreamStop(stream)
117 FSEventStreamInvalidate(stream)
118 FSEventStreamRelease(stream)