lsyncd/default-rsync.lua

175 lines
4.2 KiB
Lua
Raw Normal View History

--==================================================================================================
-- default-rsync.lua
--
-- Syncs with rsync ("classic" Lsyncd)
-- A (Layer 1) configuration.
--
-- Note:
-- this is infact just configuration using Layer 1 configuration,
-- like any other. It only gets compiled into the binary by default.
-- You can simply use a modified one, by copying everything into a
-- config file of yours and call it differently.
--
-- License: GPLv2 (see COPYING) or any later version
-- Authors: Axel Kittenberger <axkibe@gmail.com>
--
--==================================================================================================
if not default then error('default not loaded'); end
if default.rsync then error('default-rsync already loaded'); end
default.rsync = {
-----
-- Spawns rsync for a list of events
--
action = function(inlet)
-- gets all events ready for syncing
local elist = inlet.getEvents(
function(event)
return event.etype ~= 'Init' and event.etype ~= 'Blanket'
end
)
-----
-- replaces filter rule by literals
--
local function sub(p)
if not p then
return
end
return p:gsub('%?', '\\?'):
gsub('%*', '\\*'):
gsub('%[', '\\['):
gsub('%]', '\\]')
end
local paths = elist.getPaths(
function(etype, path1, path2)
if etype == 'Delete' and string.byte(path1, -1) == 47 then
return sub(path1)..'***', sub(path2)
else
return sub(path1), sub(path2)
end
end)
-- stores all filters with integer index
-- local filterI = inlet.getExcludes();
local filterI = {}
-- stores all filters with path index
local filterP = {}
-- adds one entry into the filter
-- @param path ... path to add
-- @param leaf ... true if this the original path
-- false if its a parent
local function addToFilter(path)
if filterP[path] then
return
end
filterP[path]=true
table.insert(filterI, path)
end
-- adds a path to the filter, for rsync this needs
-- to have entries for all steps in the path, so the file
-- d1/d2/d3/f1 needs filters
-- 'd1/', 'd1/d2/', 'd1/d2/d3/' and 'd1/d2/d3/f1'
for _, path in ipairs(paths) do
if path and path ~= '' then
addToFilter(path)
local pp = string.match(path, '^(.*/)[^/]+/?')
while pp do
addToFilter(pp)
pp = string.match(pp, '^(.*/)[^/]+/?')
end
end
end
local filterS = table.concat(filterI, '\n')
local filter0 = table.concat(filterI, '\000')
log('Normal', 'Calling rsync with filter-list of new/modified files/dirs\n', filterS)
local config = inlet.getConfig()
spawn(elist, config.rsyncBinary,
'<', filter0,
config.rsyncOpts,
'-r',
'--delete',
'--force',
'--from0',
'--include-from=-',
'--exclude=*',
config.source,
config.target)
end,
-----
-- Spawns the recursive startup sync
--
init = function(event)
local config = event.config;
local inlet = event.inlet;
local excludes = inlet.getExcludes();
if #excludes == 0 then
log('Normal', 'recursive startup rsync: ', config.source, ' -> ', config.target)
spawn(event, config.rsyncBinary,
'--delete',
config.rsyncOpts,
'-r',
config.source,
config.target)
else
local exS = table.concat(excludes, '\n')
log('Normal', 'recursive startup rsync: ',config.source,
' -> ',config.target,' excluding\n',exS)
spawn(event, config.rsyncBinary,
'<', exS,
'--exclude-from=-',
'--delete',
config.rsyncOpts, '-r',
config.source,
config.target)
end
end,
-----
-- Checks the configuration.
--
prepare = function(config)
if not config.target then
error('default.rsync needs "target" configured', 4)
end
if config.rsyncOps then
error('did you mean rsyncOpts with "t"?', 4)
end
-- appends a / to target if not present
if string.sub(config.target, -1) ~= '/' then
config.target = config.target..'/'
end
end,
-----
-- rsync uses default collect
----
-----
-- The rsync binary to be called.
--
rsyncBinary = '/usr/bin/rsync',
-----
-- Calls rsync with this default short opts.
--
rsyncOpts = '-lts',
-----
-- Exit codes for rsync.
--
exitcodes = default.rsyncExitCodes,
-----
-- Default delay
--
delay = 15,
}