From ec336e0ed1662c766ec452f847cef158f233f6ad Mon Sep 17 00:00:00 2001 From: Axel Kittenberger Date: Sat, 20 Nov 2010 13:10:52 +0000 Subject: [PATCH] simplifying runners Notifies implementation --- examples/limagemagic.lua | 2 +- lsyncd.lua | 273 ++++++++++++++++++++------------------- 2 files changed, 140 insertions(+), 135 deletions(-) diff --git a/examples/limagemagic.lua b/examples/limagemagic.lua index aa0fd19..1a2eb6d 100644 --- a/examples/limagemagic.lua +++ b/examples/limagemagic.lua @@ -115,5 +115,5 @@ convert = { end, } -sync{convert, source="magicdir", recursive=false} +sync{convert, source="magicdir", subdirs=false} diff --git a/lsyncd.lua b/lsyncd.lua index 7e97f54..3deb7f7 100644 --- a/lsyncd.lua +++ b/lsyncd.lua @@ -1401,6 +1401,24 @@ local Syncs = (function() end)() +----- +-- Utility function, returns the relative part of absolute path if it +-- begins with root +-- +local function splitPath(path, root) + local rl = #root + local sp = string.sub(path, 1, rl) + +print("split", path, root, sp) + + if sp == root then +print("splited", path, root, string.sub(path, rl, -1)) + return string.sub(path, rl, -1) + else + return nil + end +end + ----- -- Interface to inotify, watches recursively subdirs and -- sends events. @@ -1410,115 +1428,100 @@ end)() -- by changing this. -- local Inotifies = (function() - ----- - -- A list indexed by inotifies watch descriptor. - -- Contains a list of all syncs observing this directory - -- (directly or by recurse) - local wdlist = CountArray.new() + + ---- XXX wdlist, syncpaths + ----- - -- A list indexed by sync's containing a list of all paths - -- watches by this sync pointing to the watch descriptor. - local syncpaths = {} - - ----- - -- Adds watches for a directory including all subdirectories. + -- A list indexed by inotifies watch descriptor yielding the + -- directories absolute paths. -- - -- @param root+path directory to observe - -- @param recurse true if recursing into subdirs or - -- the relative path to root for recursed inotifies - -- @param sync link to the observer to be notified. - -- Note: Inotifies should handle this opaquely - -- @param raise if not nil creates Create events for all files/dirs - -- in this directory. Value is time for event. - local function addSync(root, path, recurse, sync, raise) + local wdpaths = CountArray.new() + + ----- + -- The same vice versa, all watch descriptors by its + -- absolute path. + -- + local pathwds = CountArray.new() + + ----- + -- A list indexed by sync's containing the root path this + -- sync is interested in. + -- + local syncRoots = {} + + ----- + -- Adds watches for a directory (optionally) including all subdirectories. + -- + -- @param path absolute path of directory to observe + -- @param recurse true if recursing into subdirs + -- @param raiseSync --X -- + -- raiseTime if not nil sends create Events for all files/dirs + -- to this sync. + -- + local function addWatch(path, recurse, raiseSync, raiseTime) log("Function", - "Inotifies.addSync(",root,", ",path,", ",recurse,", ",sync,")") + "Inotifies.addWatch(",path,", ",recurse,", ",sync,", ",raise")") - -- lets the core registers watch with the kernel - local wd = lsyncd.inotifyadd(root .. path); - if wd < 0 then - log("Error","Failure adding watch ",root,path," -> ignored ") - return + local wd = pathwds[path] + if not wd then + -- lets the core registers watch with the kernel + local wd = lsyncd.inotifyadd(path); + if wd < 0 then + log("Error","Failure adding watch ",path," -> ignored ") + return + end + pathwds[path] = wd + wdpaths[wd] = path end - -- creates a sublist in wdlist - if not wdlist[wd] then - wdlist[wd] = Array.new() - end - - -- and adds this sync to wdlist. - table.insert(wdlist[wd], { - root = root, - path = path, - recurse = recurse, - sync = sync - }) - - -- creates an entry in syncpaths to quickly retrieve - -- all entries of this sync for a path. - local sp = syncpaths[sync] - if not sp then - sp = {} - syncpaths[sync] = sp - end - sp[path] = wd - -- registers and adds watches for all subdirectories -- and/or raises create events for all entries if recurse or raise then - local entries = lsyncd.readdir(root .. path) + local entries = lsyncd.readdir(path) for dirname, isdir in pairs(entries) do local pd = path .. dirname if isdir then pd = pd .. "/" end - + -- creates a Create event for entry. - if raise then - sync:delay("Create", raise, pd, nil) + if raiseSync then + raiseSync:delay("Create", raiseTime, pd, nil) end -- adds syncs for subdirs if isdir and recurse then - addSync(root, pd, true, sync, raise) + addWatch(pd, true, raiseSync, raiseTime) end end end end ----- - -- Removes one event receiver from a directory. + -- Stops watching a directory -- - local function removeSync(sync, path) - local sp = syncpaths[sync] - if not sp then - error("internal fail, removeSync, nonexisting sync: ") - end - local wd = sp[path] + local function removeWatch(path) + local wd = pathwds[path] if not wd then - error("internal fail, removeSync, nonexisting wd.") + return end - local ilist = wdlist[wd] - if not ilist then - error("internal fail, removeSync, nonexisting ilist.") - end - -- TODO optimize for 1 entry only case - local i, found - for i, v in ipairs(ilist) do - if v.sync == sync then - found = true - break - end - end - if not found then - error("internal fail, removeSync, nonexisiting i.") - end - table.remove(ilist, i) - if #ilist == 0 then - wdlist[wd] = nil - lsyncd.inotifyrm(wd) - end - sp[path] = nil + lsyncd.inotifyrm(wd) + wdpaths[wd] = nil + pathwids[path] = nil + end + + ----- + -- adds a Sync to receive events + -- + -- @param root root dir to watch + -- @param sync Object to receive events + -- + local function addSync(root, sync) + if syncRoots[sync] then + error("internal fail, duplicate sync in Inotifies()") + end + syncRoots[sync] = root + addWatch(root, true) end ----- @@ -1533,6 +1536,7 @@ local Inotifies = (function() -- local function event(etype, wd, isdir, time, filename, wd2, filename2) local ftype; + if isdir then ftype = "directory" filename = filename .. "/" @@ -1540,6 +1544,7 @@ local Inotifies = (function() filename2 = filename2 .. "/" end end + if filename2 then log("Inotify", "got event ", etype, " ", filename, " to ", filename2) @@ -1548,80 +1553,80 @@ local Inotifies = (function() end -- looks up the watch descriptor id - local ilist = wdlist[wd] - if not ilist then + local path = wdlist[wd] + if not path then -- this is normal in case of deleted subdirs log("Inotify", "event belongs to unknown watch descriptor.") return end - local ilist2 = wd2 and wdlist[wd2] - -- works through all observers interested in this directory - for _, inotify in ipairs(ilist) do - local path = inotify.path .. filename - local path2 - local etype2 = etype - if filename2 and ilist2 then - local inotify2 - -- finds the target directory inotify/watch - for _2, i2 in ipairs(ilist2) do - if inotify.sync == i2.sync then - inotify2 = i2 - break - end - end - if not inotify2 then - log("Normal", "Transformed move to Create for ", - inotify.sync.config.name) - etype2 = "Create" - else - path2 = inotify2.path .. filename2 + local path2 = wd2 and wdpaths[wd2] + -- set to true if at least one sync wants recursive data + local recurse = false + + for sync, root in pairs(syncRoots) do repeat + local relative = splitPath(path, root) + local relative2 + if path2 then + relative2 = splitPath(path2, root) + end + if not relative and not relative2 then + -- sync is not interested in this dir + break -- continue + end + + --- checks if this sync is interested in subdirs + if isdir then + recurse = recurse or + sync.config.subdirs or + sync.config.subdirs == nil + end + + -- makes a copy of etype to possibly change it + local etyped = etype + if etyped == 'Move' then + if not relative2 then + log("Normal", "Transformed Move to Create for ", + sync.config.name) + etyped = 'Create' + elseif not relative then + relative = relative2 + relative2 = nil + log("Normal", "Transformed Move to Delete for ", + sync.config.name) + etyped = 'Delete' end end - inotify.sync:delay(etype2, time, path, path2) - - -- adds subdirs for new directories - if isdir and inotify.recurse then - if etype2 == "Create" then - addSync(inotify.root, path, true, inotify.sync, time) - elseif etype2 == "Delete" then - removeSync(inotify.sync, path) - elseif etype2 == "Move" then - removeSync(inotify.sync, path) - addSync(inotify.root, path2, true, inotify.sync, time) + sync:delay(etyped, time, relative, relative2) + + if isdir and + (sync.config.subdirs or sync.config.subdirs == nil) + then + if etyped == "Create" then + addWatch(path, true, sync, time) + elseif etyped == "Delete" then + removeWatch(path) + elseif etyped == "Move" then + removeWatch(path) + addWatch(path2, true, sync, time) end end - end - - -- TODO handle cases where a sync watches target only. XXX + until true end end ----- -- Writes a status report about inotifies to a filedescriptor -- local function statusReport(f) - f:write("Watching ",wdlist:size()," directories\n") - for wd, v in wdlist:walk() do - f:write(" ",wd,": ") - local sep = "" - for _, v in ipairs(v) do - f:write(v.root,"/",v.path or "",sep) - sep = ", " - end - f:write("\n") + f:write("Watching ",wdpaths:size()," directories\n") + for wd, path in wdpaths:walk() do + f:write(" ",wd,": ",path,"\n") end end - ----- - -- Returns the number of directories watched in total. - local function size() - return wdlist:size() - end - -- public interface return { addSync = addSync, - size = size, event = event, statusReport = statusReport }