lsyncd/default-rsync.lua

349 lines
6.4 KiB
Lua
Raw Normal View History

2012-02-15 19:10:50 +00:00
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- default-rsync.lua
--
-- Syncs with rsync ("classic" Lsyncd)
-- A (Layer 1) configuration.
--
-- Note:
2012-02-15 19:10:50 +00:00
-- this is infact just a 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
2012-02-15 19:10:50 +00:00
-- config file of yours and name it differently.
--
-- License: GPLv2 (see COPYING) or any later version
-- Authors: Axel Kittenberger <axkibe@gmail.com>
--
2012-02-15 19:10:50 +00:00
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if not default then
error('default not loaded')
end
if default.rsync then
error('default-rsync already loaded')
end
2012-10-03 16:34:09 +00:00
default.rsync = { }
2012-10-03 16:34:09 +00:00
--
-- Spawns rsync for a list of events
--
-- Exlcusions are already handled by not having
-- events for them.
--
default.rsync.action = function( inlet )
2012-10-03 16:34:09 +00:00
--
-- gets all events ready for syncing
--
local elist = inlet.getEvents(
function(event)
return event.etype ~= 'Init' and event.etype ~= 'Blanket'
end
2012-10-03 16:34:09 +00:00
)
2012-10-03 16:34:09 +00:00
--
-- Replaces what rsync would consider filter rules by literals
--
local function sub( p )
if not p then
return
end
2012-10-03 16:34:09 +00:00
return p:
gsub('%?', '\\?'):
gsub('%*', '\\*'):
gsub('%[', '\\['):
gsub('%]', '\\]')
end
2012-10-03 16:34:09 +00:00
--
-- Gets the list of paths for the event list
--
-- Deletes create multi match patterns
--
local paths = elist.getPaths(
function( etype, path1, path2 )
if string.byte( path1, -1 ) == 47 and etype == 'Delete' then
return sub( path1 )..'***', sub( path2 )
else
return sub( path1 ), sub( path2 )
end
end
2012-10-03 16:34:09 +00:00
)
2012-10-03 16:34:09 +00:00
--
-- stores all filters by integer index
--
local filterI = { }
2012-10-03 16:34:09 +00:00
--
-- Stores all filters with path index
--
local filterP = { }
--
2012-10-03 16:34:09 +00:00
-- Adds one path to the filter
--
local function addToFilter( path )
2012-10-03 16:34:09 +00:00
if filterP[ path ] then
return
end
2012-10-03 16:34:09 +00:00
filterP[ path ] = true
table.insert( filterI, path )
end
--
2012-10-03 16:34:09 +00:00
-- Adds a path to the filter.
--
-- Rsync needs to have entries for all steps in the path,
-- so the file for example d1/d2/d3/f1 needs following filters:
-- 'd1/', 'd1/d2/', 'd1/d2/d3/' and 'd1/d2/d3/f1'
--
for _, path in ipairs( paths ) do
2012-10-03 16:34:09 +00:00
if path and path ~= '' then
2012-10-03 16:34:09 +00:00
addToFilter(path)
2012-10-03 16:34:09 +00:00
local pp = string.match( path, '^(.*/)[^/]+/?' )
2012-10-03 16:34:09 +00:00
while pp do
addToFilter(pp)
pp = string.match( pp, '^(.*/)[^/]+/?' )
end
end
2012-10-03 16:34:09 +00:00
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( )
local delete = nil
if config.delete then
delete = { '--delete', '--ignore-errors' }
end
spawn(
elist,
config.rsync.binary,
'<', filter0,
config.rsync._computed,
'-r',
delete,
'--force',
'--from0',
'--include-from=-',
'--exclude=*',
config.source,
config.target
)
2012-10-03 16:34:09 +00:00
end
2012-10-03 16:34:09 +00:00
--
-- Spawns the recursive startup sync
--
init = function(event)
local config = event.config
local inlet = event.inlet
local excludes = inlet.getExcludes( )
local delete = nil
if config.delete then
delete = { '--delete', '--ignore-errors' }
end
if #excludes == 0 then
-- start rsync without any excludes
log(
'Normal',
'recursive startup rsync: ',
config.source,
' -> ',
config.target
)
2012-10-03 16:34:09 +00:00
spawn(
event,
config.rsync.binary,
delete,
config.rsync._computed,
'-r',
config.source,
config.target
)
2012-10-03 16:34:09 +00:00
else
-- start rsync providing an exclude list
-- on stdin
local exS = table.concat( excludes, '\n' )
2012-10-03 16:34:09 +00:00
log(
'Normal',
'recursive startup rsync: ',
config.source,
' -> ',
config.target,
' excluding\n',
exS
)
2012-10-03 16:34:09 +00:00
spawn(
event,
config.rsync.binary,
'<', exS,
'--exclude-from=-',
delete,
config.rsync._computed,
'-r',
config.source,
config.target
)
end
end
2012-10-03 16:34:09 +00:00
--
-- Prepares and checks a syncs configuration on startup.
--
default.rsync.prepare = function( config )
2012-10-02 06:25:46 +00:00
2012-10-03 16:34:09 +00:00
if not config.target then
error(
'default.rsync needs "target" configured',
4
)
end
2012-10-03 16:34:09 +00:00
if config.rsyncOps then
error(
'"rsyncOps" is outdated please use the new rsync = { ... } syntax.',
4
)
end
if config.rsyncOpts and config.rsync._extra then
error(
'"rsyncOpts" is outdated in favor of the new rsync = { ... } syntax\n"' +
'for which you provided the _extra attribute as well.\n"' +
'Please remove rsyncOpts from your config.',
4
)
end
2012-10-02 06:25:46 +00:00
2012-10-03 16:34:09 +00:00
if config.rsyncOpts then
log(
'Warn',
'"rsyncOpts" is outdated. Please use the new rsync = { ... } syntax."'
)
2012-10-03 16:34:09 +00:00
config.rsync._extra = config.rsyncOpts
config.rsyncOpts = nil
end
2012-10-03 16:34:09 +00:00
if config.rsyncBinary and config.rsync.binary then
error(
'"rsyncBinary is outdated in favor of the new rsync = { ... } syntax\n"'+
'for which you provided the binary attribute as well.\n"' +
"Please remove rsyncBinary from your config.'",
4
)
end
2012-10-03 16:34:09 +00:00
if config.rsyncBinary then
log(
'Warn',
'"rsyncBinary" is outdated. Please use the new rsync = { ... } syntax."'
)
2012-10-03 16:34:09 +00:00
config.rsync.binary = config.rsyncBinary
config.rsyncOpts = nil
end
2012-10-03 16:34:09 +00:00
-- checks if the _computed argument exists already
if config.rsync._computed then
error(
'please do not use the internal rsync._computed parameter',
4
)
end
-- computes the rsync arguments into one list
local rsync = config.rsync;
rsync._computed = { true }
local computed = rsync._computed
local shorts = { '-' }
if config.rsync._extra then
for k, v in ipairs( config.rsync._extra ) do
computed[ k + 1 ] = v
end
end
if rsync.links then
shorts[ #shorts + 1 ] = 'l'
end
if rsync.times then
shorts[ #shorts + 1 ] = 't'
end
if rsync.protectArgs then
shorts[ #shorts + 1 ] = 's'
end
if #shorts ~= 1 then
computed[ 1 ] = table.concat( shorts, '' )
else
computed[ 1 ] = { }
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
--
--
-- By default do deletes.
--
default.rsync.delete = true
--
-- Calls rsync with this default options
--
default.rsync.rsync = {
-- The rsync binary to be called.
binary = '/usr/bin/rsync',
links = true,
times = true,
protectArgs = true
}
2012-10-03 16:34:09 +00:00
--
-- Exit codes for rsync.
--
default.rsync.exitcodes = default.rsyncExitCodes
--
-- Default delay
--
default.rsync.delay = 15