Last active
March 16, 2016 21:56
-
-
Save sczizzo/e27d9f38f893cbeba4a8 to your computer and use it in GitHub Desktop.
Watch files, in Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'docopt' | |
require 'pathname' | |
require 'set' | |
USAGE = <<DOCOPT | |
Julio. | |
Usage: | |
julio [--interval=<seconds>] <includes>... | |
julio (-h | --help) | |
julio (-v | --version) | |
Options: | |
--interval=<seconds> Interval between loops, in seconds [default: 1]. | |
-h --help Show this screen. | |
-v --version Show version. | |
DOCOPT | |
def stat f | |
stat = File::Stat.new(f) | |
{ | |
inode: [ stat.ino, stat.dev_major, stat.dev_minor ], | |
size: stat.size, | |
mtime: stat.mtime | |
} | |
rescue Errno::ENOENT | |
nil | |
end | |
def was_appended? old_stat, new_stat | |
return false if new_stat.nil? | |
return new_stat[:size] > 0 if old_stat.nil? | |
return new_stat[:size] > old_stat[:size] | |
end | |
def was_truncated? old_stat, new_stat | |
return false if new_stat.nil? | |
return false if old_stat.nil? | |
return new_stat[:size] < old_stat[:size] | |
end | |
def was_replaced? old_stat, new_stat | |
return false if new_stat.nil? | |
return false if old_stat.nil? | |
return new_stat[:inode] != old_stat[:inode] | |
end | |
def watch includes, known | |
now_known = Set.new | |
includes.each do |i| | |
Dir.glob(i).each do |entry| | |
now_known.add Pathname.new(entry).cleanpath | |
end | |
end | |
created = now_known - known | |
deleted = known - now_known | |
return created, deleted, now_known | |
end | |
def report known, created, deleted, stats | |
deleted.each do |d| | |
puts 'report deleted:%s stat:%s' % [ | |
d.inspect, stats[d].inspect | |
] | |
end | |
created.each do |c| | |
puts 'report created:%s stat:%s' % [ | |
c.inspect, stats[c].inspect | |
] | |
end | |
new_stats = {} | |
known.each do |f| | |
new_stats[f] = stat(f) | |
if was_appended? stats[f], new_stats[f] | |
puts 'report appended:%s stat:%s' % [ | |
f.inspect, new_stats[f].inspect | |
] | |
elsif was_replaced? stats[f], new_stats[f] | |
puts 'report replaced:%s stat:%s' % [ | |
f.inspect, new_stats[f].inspect | |
] | |
elsif was_truncated? stats[f], new_stats[f] | |
puts 'report truncated:%s stat:%s' % [ | |
f.inspect, new_stats[f].inspect | |
] | |
end | |
end | |
return new_stats | |
end | |
def tail interval, includes | |
known = Set.new | |
created = Set.new | |
deleted = Set.new | |
stats = Hash.new | |
loop do | |
created, deleted, known = watch includes, known | |
stats = report known, created, deleted, stats | |
sleep interval | |
end | |
end | |
begin | |
args = Docopt::docopt(USAGE) | |
rescue Docopt::Exit => e | |
puts e.message | |
end | |
if args.nil? | |
# help mode, nop | |
elsif args['--version'] | |
puts 'VERSION' | |
elsif includes = args['<includes>'] | |
interval = args['--interval'].to_i | |
if interval < 1 | |
puts 'WARNING: Invalid <interval> provided, falling back to default...' | |
interval = 1 | |
end | |
tail interval, includes | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment