From fdfd314ebc38b7034a7fe956e8854fb35da8cd02 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 19:47:27 -0700 Subject: [PATCH] move inotify watcher to library --- bin/moonc | 98 ++++++-------------- moonscript/cmd/watcher.moon | 29 ------ moonscript/cmd/{watcher.lua => watchers.lua} | 72 +++++++++++++- moonscript/cmd/watchers.moon | 61 ++++++++++++ 4 files changed, 159 insertions(+), 101 deletions(-) delete mode 100644 moonscript/cmd/watcher.moon rename moonscript/cmd/{watcher.lua => watchers.lua} (61%) create mode 100644 moonscript/cmd/watchers.moon diff --git a/bin/moonc b/bin/moonc index 357a0f7..bc24674 100755 --- a/bin/moonc +++ b/bin/moonc @@ -194,76 +194,38 @@ local function create_watcher(files) inotify = require "inotify" end) - if inotify then - local dirs = {} + local watchers = require("moonscript.cmd.watchers") - for _, tuple in ipairs(files) do - local dir = parse_dir(tuple[1]) - 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) + if watchers.InotifyWacher:available() then + return watchers.InotifyWacher(files):each_update() 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 diff --git a/moonscript/cmd/watcher.moon b/moonscript/cmd/watcher.moon deleted file mode 100644 index afb5dd7..0000000 --- a/moonscript/cmd/watcher.moon +++ /dev/null @@ -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} diff --git a/moonscript/cmd/watcher.lua b/moonscript/cmd/watchers.lua similarity index 61% rename from moonscript/cmd/watcher.lua rename to moonscript/cmd/watchers.lua index 52be1d5..21279ba 100644 --- a/moonscript/cmd/watcher.lua +++ b/moonscript/cmd/watchers.lua @@ -31,10 +31,16 @@ remove_dupes = function(list, key_fn) return _accum_0 end)() end +local plural +plural = function(count, word) + return tostring(count) .. " " .. tostring(word) .. tostring(count == 1 and "" or "s") +end local Watcher do local _class_0 - local _base_0 = { } + local _base_0 = { + start_msg = "Starting watch loop (Ctrl-C to exit)" + } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, file_list) @@ -81,6 +87,46 @@ do dirs = _accum_0 end 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 } _base_0.__index = _base_0 @@ -125,14 +171,29 @@ end local SleepWatcher do local _class_0 + local _parent_0 = Watcher local _base_0 = { } _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) _class_0 = setmetatable({ - __init = function() end, + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, __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, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -140,6 +201,9 @@ do end }) _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end SleepWatcher = _class_0 end return { diff --git a/moonscript/cmd/watchers.moon b/moonscript/cmd/watchers.moon new file mode 100644 index 0000000..6b91aa9 --- /dev/null +++ b/moonscript/cmd/watchers.moon @@ -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}