diff --git a/CMakeLists.txt b/CMakeLists.txt index f839170..5946c90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ add_custom_command( OUTPUT signames.lua set( DEFAULT_CODE ${PROJECT_SOURCE_DIR}/default/default.lua ${PROJECT_SOURCE_DIR}/default/signal.lua + ${PROJECT_SOURCE_DIR}/default/proto.lua ${PROJECT_SOURCE_DIR}/default/rsync.lua ${PROJECT_SOURCE_DIR}/default/rsyncssh.lua ${PROJECT_SOURCE_DIR}/default/direct.lua diff --git a/ChangeLog b/ChangeLog index e12e8f6..1900fd5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,14 +3,17 @@ change: dropping /dev/fsevents hack (OSX support) change: dropping exclude and excludeFrom (replaced by filter and filterFrom) change: "insist" by default - change: removed _extra (if someone is hacky enough to really need it, they can hack Lsyncd itself) - change: user scripts run in each of their own global lua environment + change: removed _extra (if someone is hacky enough to really need it, + they can hack Lsyncd itself) + change: user scripts run in their own global lua environment + change: removed _merge + change: moved the default layer 1 functions to default.proto 2018-03-09: 2.2.3 enhaencement: supporting includes with new filter and filterFrom options change: needing now at least Lua 5.2 (Lua 5.1 no longer supported, Lua5.3 supported) change: if the target/targetdir ends with a ':' do not append - a trailing '/' to it, since that would change it from homedir to rootdir! + . a trailing '/' to it, since that would change it from homedir to rootdir! add: example for Amazon S3 Bucket (Daniel Miranda) fix: setting stdout/stderr to linebuffer mode. fix: Lua5.3 compatiblity, using load() instead of loadstring() diff --git a/default/default.lua b/default/default.lua index 5608ea4..e2ed1ff 100644 --- a/default/default.lua +++ b/default/default.lua @@ -1,8 +1,7 @@ --============================================================================ -- default.lua Live (Mirror) Syncing Demon -- --- The default table for the user to access. --- This default layer 1 functions provide the higher layer functionality. +-- The default global. -- -- License: GPLv2 (see COPYING) or any later version -- Authors: Axel Kittenberger @@ -13,327 +12,3 @@ if default then error( 'default already loaded' ) end default = { } - - --- --- Only this items are inherited from the default --- table --- -default._merge = -{ - action = true, - checkgauge = true, - collect = true, - delay = true, - init = true, - maxDelays = true, - maxProcesses = true, - prepare = true, -} - --- --- used to ensure there aren't typos in the keys --- -default.checkgauge = -{ - action = true, - checkgauge = true, - collect = true, - delay = true, - exitcodes = true, - init = true, - maxDelays = true, - maxProcesses = true, - onAttrib = true, - onCreate = true, - onModify = true, - onDelete = true, - onStartup = true, - onMove = true, - prepare = true, - source = true, - target = true, -} - --- --- On default action the user's on*** scripts are called. --- -default.action = function -( - inlet -- the inlet of the active sync. -) - -- in case of moves getEvent returns the origin and dest of the move - local event, event2 = inlet.getEvent( ) - - local config = inlet.getConfig( ) - - local func = config[ 'on'.. event.etype ] - - if type( func ) == 'function' - then - func( event, event2 ) - end - - -- if function didnt change the wait status its not interested - -- in this event -> drop it. - if event.status == 'wait' - then - inlet.discardEvent( event ) - end - -end - - --- --- Default collector. --- --- Called when collecting a finished child process --- -default.collect = function -( - agent, -- event or event list being collected - exitcode -- the exitcode of the spawned process -) - local config = agent.config - - local rc - - if agent.syncStopped - then - log( 'Normal', 'Sync stopped, ignoring exitcode of finished child' ) - return 'ok' - end - - if config.exitcodes - then - rc = config.exitcodes[ exitcode ] - elseif exitcode == 0 - then - rc = 'ok' - else - rc = 'die' - end - - -- TODO synchronize with similar code before - if not agent.isList and agent.etype == 'Init' - then - if rc == 'ok' - then - log( - 'Normal', - 'Startup of ',agent.source, ' -> ',agent.target,' finished.' - ) - - return 'ok' - elseif rc == 'again' - then - if settings( 'insist' ) - then - log( - 'Normal', - 'Retrying startup of ', - agent.source, ' -> ', agent.target, - ': ', exitcode - ) - - return 'again' - end - elseif rc == 'die' - then - log( - 'Error', - 'Failure on startup of ', - agent.source, ' -> ', agent.target - ) - - terminate( -1 ) - else - log( - 'Error', - 'Unknown exitcode "', exitcode, - '" on startup of ', - agent.source, ' -> ', agent.target - ) - return 'die' - end - end - - if agent.isList - then - if rc == 'ok' - then - log( 'Normal', 'Finished a list after exitcode: ', exitcode ) - elseif rc == 'again' - then - log( 'Normal', 'Retrying a list after exitcode = ', exitcode ) - elseif rc == 'die' - then - log( 'Error', 'Failure with a list with exitcode = ', exitcode ) - else - log( 'Error', 'Unknown exitcode "', exitcode, '" with a list' ) - - rc = 'die' - end - else - if rc == 'ok' - then - log( - 'Normal', - 'Finished ', agent.etype, - ' on ', agent.sourcePath, ' = ', exitcode - ) - elseif rc == 'again' - then - log( - 'Normal', - 'Retrying ', agent.etype, - ' on ', agent.sourcePath, ' = ', exitcode - ) - elseif rc == 'die' - then - log( 'Error', - 'Failure with ', agent.etype, - ' on ', agent.sourcePath, ' = ', exitcode - ) - else - log( - 'Normal', - 'Unknown exitcode "', exitcode, - '" with ', agent.etype, - ' on ', agent.sourcePath, ' = ', exitcode - ) - - rc = 'die' - end - end - - return rc -end - - --- --- Called on the Init event sent --- on (re)initialization of Lsyncd for every sync --- -default.init = function -( - event -- the precreated init event. -) - local config = event.config - - local inlet = event.inlet - - -- user functions - -- calls a startup if given by user script. - if type( config.onStartup ) == 'function' - then - config.onStartup( event ) - -- TODO honor some return codes of startup like "warmstart". - end - - if event.status == 'wait' - then - -- user script did not spawn anything - -- thus the blanket event is deleted again. - inlet.discardEvent( event ) - end -end - - --- --- The collapsor tries not to have more than these delays. --- So the delay queue does not grow too large --- since calculation for stacking events is n*log( n ) (or so) --- -default.maxDelays = 1000 - - --- --- The maximum number of processes Lsyncd will --- simultanously spawn for this sync. --- -default.maxProcesses = 1 - - - --- --- Exitcodes of ssh and what to do. --- -default.sshExitCodes = -{ - -- - -- if another config provides the same table - -- this will not be inherited (merged) into that one - -- - -- if it does not, integer keys are to be copied - -- verbatim - -- - _merge = false, - _verbatim = true, - - [ 0 ] = 'ok', - [ 255 ] = 'again', -} - - --- --- Minimum seconds between two writes of the status file. --- -default.statusInterval = 10 - - --- --- Checks all keys to be in the checkgauge. --- -local function check -( - config, - gauge, - subtable, - level -) - for k, v in pairs( config ) - do - if not gauge[ k ] - then - error( - 'Parameter "' .. subtable .. k .. '" unknown.' - .. ' ( if this is not a typo add it to checkgauge )', - level - ); - end - - if type( gauge [ k ] ) == 'table' - then - if type( v ) ~= 'table' - then - error( - 'Parameter "' .. subtable .. k .. '" must be a table.', - level - ) - end - - check( - config[ k ], - gauge[ k ], - subtable .. k .. '.', - level + 1 - ) - end - end -end - - -default.prepare = function -( - config, -- the config to prepare for - level -- current callback level for error reporting -) - - local gauge = config.checkgauge - - if not gauge then return end - - check( config, gauge, '', level + 1 ) -end - diff --git a/default/rsync.lua b/default/rsync.lua index 347f49b..5f72c68 100644 --- a/default/rsync.lua +++ b/default/rsync.lua @@ -393,23 +393,17 @@ rsync.prepare = function skipTarget -- used by rsyncssh, do not check for target ) -- First let default.prepare test the checkgauge - default.prepare( config, level + 6 ) + default.proto.prepare( config, level + 6 ) if not skipTarget and not config.target then - error( - 'default.rsync needs "target" configured', - level - ) + error( 'default.rsync needs "target" configured', level ) end -- checks if the _computed argument exists already if config.rsync._computed then - error( - 'please do not use the internal rsync._computed parameter', - level - ) + error( 'please do not use the internal rsync._computed parameter', level ) end -- computes the rsync arguments into one list diff --git a/default/rsyncssh.lua b/default/rsyncssh.lua index 04c6101..d9746d9 100644 --- a/default/rsyncssh.lua +++ b/default/rsyncssh.lua @@ -568,12 +568,26 @@ rsyncssh.exitcodes = false -- -- rsync exit codes -- -rsyncssh.rsyncExitCodes = rsync.exitCodes +rsyncssh.rsyncExitCodes = default.rsync.exitCodes -- --- ssh exit codes +-- Exitcodes of ssh and what to do. -- -rsyncssh.sshExitCodes = default.sshExitCodes +rsyncssh.sshExitCodes = +{ + -- + -- if another config provides the same table + -- this will not be inherited (merged) into that one + -- + -- if it does not, integer keys are to be copied + -- verbatim + -- + _merge = false, + _verbatim = true, + + [ 0 ] = 'ok', + [ 255 ] = 'again', +} -- diff --git a/mantle/mci.lua b/mantle/mci.lua index e320a4d..10b06e0 100644 --- a/mantle/mci.lua +++ b/mantle/mci.lua @@ -25,6 +25,12 @@ now = core.now readdir = core.readdir +-- +-- Minimum seconds between two writes of the status file. +-- +local defaultStatusInterval = 10 + + -- -- Global: total number of processess running. -- @@ -432,7 +438,7 @@ function mci.initialize -- if uSettings.statusInterval == nil then - uSettings.statusInterval = userenv.default.statusInterval + uSettings.statusInterval = defaultStatusInterval end -- makes sure the user gave Lsyncd anything to do diff --git a/mantle/syncmaster.lua b/mantle/syncmaster.lua index bb8b429..f30e904 100644 --- a/mantle/syncmaster.lua +++ b/mantle/syncmaster.lua @@ -108,14 +108,9 @@ local function inherit -- non-integer keys for k, v in pairs( cs ) do - if ( - type( k ) ~= 'number' - or verbatim - or cs._verbatim == true - ) and ( - type( cs._merge ) ~= 'table' - or cs._merge[ k ] == true - ) + if type( k ) ~= 'number' + or verbatim + or cs._verbatim == true then inheritKV( cd, k, v ) end @@ -149,7 +144,7 @@ inheritKV = ) -- don't merge inheritance controls - if k == '_merge' or k == '_verbatim' then return end + if k == '_verbatim' then return end local dtype = type( cd [ k ] ) @@ -159,9 +154,7 @@ inheritKV = then cd[ k ] = { } inherit( cd[ k ], v, k == 'exitcodes' ) - elseif - dtype == 'table' and - v._merge ~= false + elseif dtype == 'table' then inherit( cd[ k ], v, k == 'exitcodes' ) end @@ -187,8 +180,8 @@ local function add inherit( config, uconfig ) - -- last and least defaults are inherited - inherit( config, userenv.default ) + -- last and least default prototype is inherited + inherit( config, userenv.default.proto ) local inheritSettings = {