lsyncd/default/rsync.lua

654 lines
13 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
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-03-01 10:26:12 +00:00
if not default then error( 'default not loaded' ) end
2018-03-01 10:26:12 +00:00
if default.rsync then error( 'default-rsync already loaded' ) end
local rsync = { }
2015-10-14 12:39:14 +00:00
default.rsync = rsync
-- uses default collect
--
-- used to ensure there aren't typos in the keys
--
rsync.checkgauge = {
-- unsets default user action handlers
onCreate = false,
onModify = false,
onDelete = false,
onStartup = false,
onMove = false,
delete = true,
exclude = true,
excludeFrom = true,
2018-02-27 16:14:36 +00:00
filter = true,
filterFrom = true,
target = true,
rsync = {
acls = true,
2016-12-05 14:47:12 +00:00
append = true,
append_verify = true,
archive = true,
backup = true,
backup_dir = true,
binary = true,
2013-06-07 09:11:42 +00:00
bwlimit = true,
checksum = true,
2016-08-29 11:12:09 +00:00
chown = true,
2016-12-01 13:12:56 +00:00
chmod = true,
compress = true,
2016-12-01 11:35:02 +00:00
copy_dirlinks = true,
copy_links = true,
cvs_exclude = true,
dry_run = true,
executability = true,
2016-11-28 10:20:12 +00:00
existing = true,
2014-02-28 09:15:48 +00:00
group = true,
2016-12-05 14:25:58 +00:00
groupmap = true,
hard_links = true,
ignore_times = true,
2015-10-14 12:39:14 +00:00
inplace = true,
ipv4 = true,
ipv6 = true,
keep_dirlinks = true,
links = true,
one_file_system = true,
2016-05-04 09:25:40 +00:00
omit_dir_times = true,
omit_link_times = true,
owner = true,
password_file = true,
perms = true,
protect_args = true,
prune_empty_dirs = true,
quiet = true,
rsh = true,
rsync_path = true,
sparse = true,
suffix = true,
2012-10-23 05:23:58 +00:00
temp_dir = true,
2013-03-19 07:25:29 +00:00
timeout = true,
2014-02-28 09:15:48 +00:00
times = true,
update = true,
2016-12-05 14:25:58 +00:00
usermap = true,
verbose = true,
2014-02-28 09:15:48 +00:00
whole_file = true,
xattrs = true,
},
}
2017-01-03 12:08:48 +00:00
--
-- Returns true for non Init and Blanket events.
--
local eventNotInitBlank =
function
(
event
)
return event.etype ~= 'Init' and event.etype ~= 'Blanket'
end
2012-10-03 16:34:09 +00:00
--
-- Spawns rsync for a list of events
--
2016-05-24 03:39:10 +00:00
-- Exclusions are already handled by not having
2012-10-03 16:34:09 +00:00
-- events for them.
--
rsync.action = function
(
inlet
)
local config = inlet.getConfig( )
2012-10-03 16:34:09 +00:00
-- gets all events ready for syncing
2017-01-03 12:08:48 +00:00
local elist = inlet.getEvents( eventNotInitBlank )
2017-01-03 12:08:48 +00:00
-- gets the list of paths for the event list
-- deletes create multi match patterns
2017-01-05 09:02:16 +00:00
local paths = elist.getPaths( )
2012-10-03 16:34:09 +00:00
--
-- Replaces what rsync would consider filter rules by literals
--
2018-02-27 16:14:36 +00:00
local function sub
(
p -- pattern
)
if not p then return end
return p:
gsub( '%?', '\\?' ):
gsub( '%*', '\\*' ):
gsub( '%[', '\\[' ):
gsub( '%]', '\\]' )
end
--
2018-05-11 07:07:03 +00:00
-- Gets the list of paths for the event list.
--
-- Deletes create multi match patterns
--
local paths = elist.getPaths(
2018-02-27 16:14:36 +00:00
function
(
etype, -- event type
path1, -- path
path2 -- path to for move events
)
if string.byte( path1, -1 ) == 47 and etype == 'Delete'
then
return sub( path1 )..'***', sub( path2 )
else
return sub( path1 ), sub( path2 )
end
end
)
-- stores all filters by integer index
local filterI = { }
-- stores all filters with path index
local filterP = { }
-- adds one path to the filter
2018-02-27 16:14:36 +00:00
local function addToFilter
(
path
)
if filterP[ path ] then return end
filterP[ path ] = true
table.insert( filterI, path )
end
-- 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'
2018-02-27 16:14:36 +00:00
for _, path in ipairs( paths )
do
if path and path ~= ''
then
addToFilter( path )
local pp = string.match( path, '^(.*/)[^/]+/?' )
2018-02-27 16:14:36 +00:00
while pp
do
addToFilter( pp )
pp = string.match( pp, '^(.*/)[^/]+/?' )
end
end
2012-10-03 16:34:09 +00:00
end
log(
'Normal',
'Calling rsync with filter-list of new/modified files/dirs\n',
table.concat( filterI, '\n' )
2012-10-03 16:34:09 +00:00
)
local config = inlet.getConfig( )
2012-10-03 16:34:09 +00:00
local delete = nil
if config.delete == true or config.delete == 'running'
then
delete = { '--delete', '--ignore-errors' }
2012-10-03 16:34:09 +00:00
end
spawn(
elist,
config.rsync.binary,
'<', table.concat( filterI, '\000' ),
2012-10-03 16:34:09 +00:00
config.rsync._computed,
'-r',
2012-10-03 16:34:09 +00:00
delete,
'--force',
'--from0',
'--include-from=-',
'--exclude=*',
2012-10-03 16:34:09 +00:00
config.source,
config.target
)
end
----
---- NOTE: This optimized version can be used once
---- https://bugzilla.samba.org/show_bug.cgi?id=12569
---- is fixed.
----
---- Spawns rsync for a list of events
----
---- Exclusions are already handled by not having
---- events for them.
----
--rsync.action = function
--(
-- inlet
--)
-- local config = inlet.getConfig( )
--
-- -- gets all events ready for syncing
-- local elist = inlet.getEvents( eventNotInitBlank )
--
-- -- gets the list of paths for the event list
-- -- deletes create multi match patterns
-- local paths = elist.getPaths( )
--
-- -- removes trailing slashes from dirs.
-- for k, v in ipairs( paths )
-- do
-- if string.byte( v, -1 ) == 47
-- then
-- paths[ k ] = string.sub( v, 1, -2 )
-- end
-- end
--
-- log(
-- 'Normal',
-- 'Calling rsync with filter-list of new/modified files/dirs\n',
-- table.concat( paths, '\n' )
-- )
--
-- local delete = nil
--
-- if config.delete == true
-- or config.delete == 'running'
-- then
-- delete = { '--delete-missing-args', '--ignore-errors' }
-- end
--
-- spawn(
-- elist,
-- config.rsync.binary,
-- '<', table.concat( paths, '\000' ),
-- config.rsync._computed,
-- delete,
-- '--force',
-- '--from0',
-- '--files-from=-',
-- config.source,
-- config.target
-- )
--end
2012-10-03 16:34:09 +00:00
--
-- Spawns the recursive startup sync.
2012-10-03 16:34:09 +00:00
--
rsync.init = function
(
event
)
local config = event.config
local inlet = event.inlet
2018-02-27 16:14:36 +00:00
local filters = inlet.hasFilters( ) and inlet.getFilters( )
local delete = nil
local target = config.target
2016-12-05 14:47:12 +00:00
if not target
then
if not config.host
then
error('Internal fail, Neither target nor host is configured')
end
target = config.host .. ':' .. config.targetdir
end
2012-10-03 16:34:09 +00:00
if config.delete == true
or config.delete == 'startup'
2016-12-05 14:47:12 +00:00
then
2012-10-03 16:34:09 +00:00
delete = { '--delete', '--ignore-errors' }
end
2018-03-14 08:57:49 +00:00
if not filters
2016-12-05 14:47:12 +00:00
then
2018-03-14 08:57:49 +00:00
-- starts rsync without any filters
2012-10-03 16:34:09 +00:00
log(
'Normal',
'recursive startup rsync: ',
config.source,
' -> ',
target
2012-10-03 16:34:09 +00:00
)
2012-10-03 16:34:09 +00:00
spawn(
event,
config.rsync.binary,
delete,
config.rsync._computed,
'-r',
config.source,
target
2012-10-03 16:34:09 +00:00
)
2018-02-27 16:14:36 +00:00
else
-- starts rsync providing a filter list
-- on stdin
local fS = table.concat( filters, '\n' )
log(
'Normal',
'recursive startup rsync: ',
config.source,
' -> ',
target,
' filtering\n',
fS
)
spawn(
event,
config.rsync.binary,
'<', fS,
'--filter=. -',
delete,
config.rsync._computed,
'-r',
config.source,
target
)
2012-10-03 16:34:09 +00:00
end
end
2012-10-03 16:34:09 +00:00
--
-- Prepares and checks a syncs configuration on startup.
--
rsync.prepare = function
(
config, -- the configuration
level, -- additional error level for inherited use ( by rsyncssh )
skipTarget -- used by rsyncssh, do not check for target
)
-- First let default.prepare test the checkgauge
default.prepare( config, level + 6 )
2012-10-02 06:25:46 +00:00
2015-10-14 12:39:14 +00:00
if not skipTarget and not config.target
then
2012-10-03 16:34:09 +00:00
error(
'default.rsync needs "target" configured',
level
2012-10-03 16:34:09 +00:00
)
end
2012-10-03 16:34:09 +00:00
-- checks if the _computed argument exists already
2015-10-14 12:39:14 +00:00
if config.rsync._computed
then
2012-10-03 16:34:09 +00:00
error(
'please do not use the internal rsync._computed parameter',
level
2012-10-03 16:34:09 +00:00
)
end
-- computes the rsync arguments into one list
2012-10-06 12:22:08 +00:00
local crsync = config.rsync;
-- everything implied by archive = true
local archiveFlags = {
recursive = true,
links = true,
perms = true,
times = true,
group = true,
owner = true,
devices = true,
specials = true,
hard_links = false,
acls = false,
xattrs = false,
}
2014-02-28 09:15:48 +00:00
-- if archive is given the implications are filled in
2015-10-14 12:39:14 +00:00
if crsync.archive
then
for k, v in pairs( archiveFlags )
do
if crsync[ k ] == nil
then
2012-10-06 12:22:08 +00:00
crsync[ k ] = v
end
end
end
crsync._computed = { true }
2016-12-05 14:25:58 +00:00
2012-10-06 12:22:08 +00:00
local computed = crsync._computed
2016-12-05 14:25:58 +00:00
local computedN = 2
local shortFlags = {
acls = 'A',
backup = 'b',
checksum = 'c',
compress = 'z',
2016-12-01 11:35:02 +00:00
copy_dirlinks = 'k',
copy_links = 'L',
cvs_exclude = 'C',
dry_run = 'n',
executability = 'E',
2014-02-28 09:15:48 +00:00
group = 'g',
hard_links = 'H',
ignore_times = 'I',
ipv4 = '4',
ipv6 = '6',
keep_dirlinks = 'K',
links = 'l',
one_file_system = 'x',
2016-05-04 09:25:40 +00:00
omit_dir_times = 'O',
omit_link_times = 'J',
owner = 'o',
perms = 'p',
protect_args = 's',
prune_empty_dirs = 'm',
quiet = 'q',
sparse = 'S',
2014-02-28 09:15:48 +00:00
times = 't',
update = 'u',
verbose = 'v',
2014-02-28 09:15:48 +00:00
whole_file = 'W',
xattrs = 'X',
}
2012-10-03 16:34:09 +00:00
local shorts = { '-' }
local shortsN = 2
2012-10-03 16:34:09 +00:00
2015-10-14 12:39:14 +00:00
for k, flag in pairs( shortFlags )
do
if crsync[ k ]
then
shorts[ shortsN ] = flag
shortsN = shortsN + 1
end
2012-10-03 16:34:09 +00:00
end
2015-10-14 12:39:14 +00:00
if crsync.devices and crsync.specials
then
2012-10-06 12:22:08 +00:00
shorts[ shortsN ] = 'D'
shortsN = shortsN + 1
else
2015-10-14 12:39:14 +00:00
if crsync.devices
then
2012-10-06 12:22:08 +00:00
computed[ computedN ] = '--devices'
computedN = computedN + 1
end
2015-10-14 12:39:14 +00:00
if crsync.specials
then
2012-10-06 12:22:08 +00:00
computed[ computedN ] = '--specials'
computedN = computedN + 1
end
end
2016-12-05 14:47:12 +00:00
if crsync.append
then
computed[ computedN ] = '--append'
computedN = computedN + 1
end
2016-12-14 07:45:33 +00:00
2016-12-05 14:47:12 +00:00
if crsync.append_verify
then
computed[ computedN ] = '--append-verify'
computedN = computedN + 1
end
2016-12-14 07:45:33 +00:00
if crsync.backup_dir
then
computed[ computedN ] = '--backup-dir=' .. crsync.backup_dir
computedN = computedN + 1
end
2016-12-05 14:47:12 +00:00
2015-10-14 12:39:14 +00:00
if crsync.bwlimit
then
2013-06-07 09:11:42 +00:00
computed[ computedN ] = '--bwlimit=' .. crsync.bwlimit
computedN = computedN + 1
end
2012-10-06 12:22:08 +00:00
2016-12-01 13:12:56 +00:00
if crsync.chmod
then
computed[ computedN ] = '--chmod=' .. crsync.chmod
computedN = computedN + 1
end
2016-08-29 11:12:09 +00:00
if crsync.chown
then
computed[ computedN ] = '--chown=' .. crsync.chown
computedN = computedN + 1
end
2016-12-14 07:45:33 +00:00
2016-12-05 14:25:58 +00:00
if crsync.groupmap
then
computed[ computedN ] = '--groupmap=' .. crsync.groupmap
computedN = computedN + 1
end
2016-12-14 07:45:33 +00:00
2016-11-28 10:20:12 +00:00
if crsync.existing
then
computed[ computedN ] = '--existing'
computedN = computedN + 1
end
2016-08-29 11:12:09 +00:00
2015-10-14 12:39:14 +00:00
if crsync.inplace
then
computed[ computedN ] = '--inplace'
computedN = computedN + 1
end
if crsync.password_file
then
computed[ computedN ] = '--password-file=' .. crsync.password_file
computedN = computedN + 1
end
2015-10-14 12:39:14 +00:00
if crsync.rsh
then
computed[ computedN ] = '--rsh=' .. crsync.rsh
computedN = computedN + 1
2012-10-03 16:34:09 +00:00
end
2015-10-14 12:39:14 +00:00
if crsync.rsync_path
then
computed[ computedN ] = '--rsync-path=' .. crsync.rsync_path
computedN = computedN + 1
2012-10-03 16:34:09 +00:00
end
if crsync.suffix
then
computed[ computedN ] = '--suffix=' .. crsync.suffix
computedN = computedN + 1
end
2015-10-14 12:39:14 +00:00
if crsync.temp_dir
then
computed[ computedN ] = '--temp-dir=' .. crsync.temp_dir
2012-10-23 05:23:58 +00:00
computedN = computedN + 1
end
2015-10-14 12:39:14 +00:00
if crsync.timeout
then
2013-03-19 07:25:29 +00:00
computed[ computedN ] = '--timeout=' .. crsync.timeout
computedN = computedN + 1
end
2016-12-14 07:45:33 +00:00
2016-12-05 14:25:58 +00:00
if crsync.usermap
then
computed[ computedN ] = '--usermap=' .. crsync.usermap
computedN = computedN + 1
end
2013-03-19 07:25:29 +00:00
2015-10-14 12:39:14 +00:00
if shortsN ~= 2
then
2012-10-03 16:34:09 +00:00
computed[ 1 ] = table.concat( shorts, '' )
else
computed[ 1 ] = { }
end
-- appends a / to target if not present
-- and not a ':' for home dir.
if not skipTarget
and string.sub( config.target, -1 ) ~= '/'
and string.sub( config.target, -1 ) ~= ':'
2015-10-14 12:39:14 +00:00
then
2012-10-03 16:34:09 +00:00
config.target = config.target..'/'
end
end
2012-10-03 16:34:09 +00:00
--
-- By default do deletes.
--
rsync.delete = true
--
-- Rsyncd exitcodes
--
rsync.exitcodes = default.rsyncExitCodes
2012-10-03 16:34:09 +00:00
--
-- Calls rsync with this default options
--
2015-10-14 12:39:14 +00:00
rsync.rsync =
{
2012-10-03 16:34:09 +00:00
-- The rsync binary to be called.
binary = '/usr/bin/rsync',
links = true,
times = true,
protect_args = true
}
2012-10-03 16:34:09 +00:00
--
-- Default delay
--
rsync.delay = 15