move inotify watcher to library

This commit is contained in:
leaf corcoran 2016-04-13 19:47:27 -07:00
parent c5cbf3315e
commit fdfd314ebc
4 changed files with 159 additions and 101 deletions

View File

@ -194,76 +194,38 @@ local function create_watcher(files)
inotify = require "inotify" inotify = require "inotify"
end) end)
if inotify then local watchers = require("moonscript.cmd.watchers")
local dirs = {}
for _, tuple in ipairs(files) do if watchers.InotifyWacher:available() then
local dir = parse_dir(tuple[1]) return watchers.InotifyWacher(files):each_update()
if dir == "" then
dir = "./"
end
table.insert(dirs, dir)
end
dirs = remove_dups(dirs)
return coroutine.wrap(function()
io.stderr:write(("%s with inotify [%s]"):format(msg, plural(#dirs, "dir")) .. "\n")
local wd_table = {}
local handle = inotify.init()
for _, dir in ipairs(dirs) do
local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO)
wd_table[wd] = dir
end
while true do
local events = handle:read()
if not events then
break
end
for _, ev in ipairs(events) do
local fname = ev.name
if fname:match("%.moon$") then
local dir = wd_table[ev.wd]
if dir ~= "./" then
fname = dir .. fname
end
-- TODO: check to make sure the file was in the original set
coroutine.yield(fname)
end
end
end
end)
else
-- poll the filesystem instead
local sleep = get_sleep_func()
return coroutine.wrap(function()
io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n")
local mod_time = {}
while true do
for _, tuple in ipairs(files) do
local file = tuple[1]
local time = lfs.attributes(file, "modification")
if not time then
mod_time[file] = nil -- file doesn't exist
elseif not mod_time[file] then
mod_time[file] = time -- new file created
else
if time ~= mod_time[file] then
if time > mod_time[file] then
coroutine.yield(file)
mod_time[file] = time
end
end
end
end
sleep(polling_rate)
end
end)
end end
-- poll the filesystem instead
local sleep = get_sleep_func()
return coroutine.wrap(function()
io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n")
local mod_time = {}
while true do
for _, tuple in ipairs(files) do
local file = tuple[1]
local time = lfs.attributes(file, "modification")
if not time then
mod_time[file] = nil -- file doesn't exist
elseif not mod_time[file] then
mod_time[file] = time -- new file created
else
if time ~= mod_time[file] then
if time > mod_time[file] then
coroutine.yield(file)
mod_time[file] = time
end
end
end
end
sleep(polling_rate)
end
end)
end end

View File

@ -1,29 +0,0 @@
remove_dupes = (list, key_fn) ->
seen = {}
return for item in *list
key = if key_fn then key_fn item else item
continue if seen[key]
seen[key] = true
item
-- files is a list of tuples, {source, target}
class Watcher
new: (@file_list) =>
class InotifyWacher extends Watcher
@available: =>
pcall -> require "inotify"
get_dirs: =>
import parse_dir from require "moonscript.cmd.moonc"
dirs = for {file_path} in *@file_list
dir = parse_dir file_path
dir = "./" if dir == ""
dir
remove_dupes dirs
class SleepWatcher
{:Watcher, :SleepWatcher, :InotifyWacher}

View File

@ -31,10 +31,16 @@ remove_dupes = function(list, key_fn)
return _accum_0 return _accum_0
end)() end)()
end end
local plural
plural = function(count, word)
return tostring(count) .. " " .. tostring(word) .. tostring(count == 1 and "" or "s")
end
local Watcher local Watcher
do do
local _class_0 local _class_0
local _base_0 = { } local _base_0 = {
start_msg = "Starting watch loop (Ctrl-C to exit)"
}
_base_0.__index = _base_0 _base_0.__index = _base_0
_class_0 = setmetatable({ _class_0 = setmetatable({
__init = function(self, file_list) __init = function(self, file_list)
@ -81,6 +87,46 @@ do
dirs = _accum_0 dirs = _accum_0
end end
return remove_dupes(dirs) return remove_dupes(dirs)
end,
each_update = function(self)
return coroutine.wrap(function()
local dirs = self:get_dirs()
io.stderr:write(tostring(self.start_msg) .. " with inotify [" .. tostring(plural(#dirs, "dir")) .. "]\n")
local wd_table = { }
local inotify = require("inotify")
local handle = inotify.init()
for _index_0 = 1, #dirs do
local dir = dirs[_index_0]
local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO)
wd_table[wd] = dir
end
while true do
local events = handle:read()
if not (events) then
break
end
for _index_0 = 1, #events do
local _continue_0 = false
repeat
local ev = events[_index_0]
local fname = ev.name
if not (fname:match("%.moon$")) then
_continue_0 = true
break
end
local dir = wd_table[ev.wd]
if dir ~= "./" then
fname = dir .. fname
end
coroutine.yield(fname)
_continue_0 = true
until true
if not _continue_0 then
break
end
end
end
end)
end end
} }
_base_0.__index = _base_0 _base_0.__index = _base_0
@ -125,14 +171,29 @@ end
local SleepWatcher local SleepWatcher
do do
local _class_0 local _class_0
local _parent_0 = Watcher
local _base_0 = { } local _base_0 = { }
_base_0.__index = _base_0 _base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({ _class_0 = setmetatable({
__init = function() end, __init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0, __base = _base_0,
__name = "SleepWatcher" __name = "SleepWatcher",
__parent = _parent_0
}, { }, {
__index = _base_0, __index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...) __call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0) local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...) cls.__init(_self_0, ...)
@ -140,6 +201,9 @@ do
end end
}) })
_base_0.__class = _class_0 _base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
SleepWatcher = _class_0 SleepWatcher = _class_0
end end
return { return {

View File

@ -0,0 +1,61 @@
remove_dupes = (list, key_fn) ->
seen = {}
return for item in *list
key = if key_fn then key_fn item else item
continue if seen[key]
seen[key] = true
item
plural = (count, word) ->
"#{count} #{word}#{count == 1 and "" or "s"}"
-- files is a list of tuples, {source, target}
class Watcher
start_msg: "Starting watch loop (Ctrl-C to exit)"
new: (@file_list) =>
class InotifyWacher extends Watcher
@available: =>
pcall -> require "inotify"
get_dirs: =>
import parse_dir from require "moonscript.cmd.moonc"
dirs = for {file_path} in *@file_list
dir = parse_dir file_path
dir = "./" if dir == ""
dir
remove_dupes dirs
-- creates an iterator that yields a file every time it's updated
-- TODO: detect when new files are added to directories
each_update: =>
coroutine.wrap ->
dirs = @get_dirs!
io.stderr\write "#{@start_msg} with inotify [#{plural #dirs, "dir"}]\n"
wd_table = {}
inotify = require "inotify"
handle = inotify.init!
for dir in *dirs
wd = handle\addwatch dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO
wd_table[wd] = dir
while true
events = handle\read!
break unless events -- error?
for ev in *events
fname = ev.name
continue unless fname\match "%.moon$"
dir = wd_table[ev.wd]
fname = dir .. fname if dir != "./"
-- TODO: check to make sure the file was in the original set
coroutine.yield(fname)
class SleepWatcher extends Watcher
{:Watcher, :SleepWatcher, :InotifyWacher}