mirror of
https://github.com/octoleo/lsyncd.git
synced 2024-12-13 14:43:09 +00:00
code beautifications
This commit is contained in:
parent
698c5c3e4d
commit
899077ccd7
398
lsyncd.lua
398
lsyncd.lua
@ -5,6 +5,8 @@
|
||||
-- It works closely together with the Lsyncd core in lsyncd.c. This means it
|
||||
-- cannot be runned directly from the standard lua interpreter.
|
||||
--
|
||||
-- This code assumes your editor is at least 100 chars wide.
|
||||
--
|
||||
-- License: GPLv2 (see COPYING) or any later version
|
||||
-- Authors: Axel Kittenberger <axkibe@gmail.com>
|
||||
--
|
||||
@ -18,10 +20,16 @@
|
||||
-- The core will exit if version ids mismatch.
|
||||
--
|
||||
if lsyncd_version then
|
||||
-- checks if the runner is being loaded twice
|
||||
lsyncd.log('Error', 'You cannot use the lsyncd runner as configuration file!')
|
||||
lsyncd.terminate(-1) -- ERRNO
|
||||
|
||||
-- ensures the runner is not being loaded twice
|
||||
lsyncd.log(
|
||||
'Error',
|
||||
'You cannot use the lsyncd runner as configuration file!'
|
||||
)
|
||||
|
||||
lsyncd.terminate( -1 )
|
||||
end
|
||||
|
||||
lsyncd_version = '2.0.7'
|
||||
|
||||
--
|
||||
@ -1352,7 +1360,7 @@ local Excludes = ( function( )
|
||||
err
|
||||
)
|
||||
|
||||
terminate(-1) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
for line in f:lines() do
|
||||
@ -1521,7 +1529,7 @@ local Sync = ( function( )
|
||||
|
||||
if rc == 'die' then
|
||||
log( 'Error', 'Critical exitcode.' );
|
||||
terminate( -1 ) --ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
if rc ~= 'again' then
|
||||
@ -1562,7 +1570,7 @@ local Sync = ( function( )
|
||||
|
||||
if rc == 'die' then
|
||||
log( 'Error', 'Critical exitcode.' );
|
||||
terminate( -1 ) --ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
if rc == 'again' then
|
||||
@ -2188,7 +2196,7 @@ local Syncs = ( function( )
|
||||
info.short_src,':',
|
||||
info.currentline,': source missing from sync.'
|
||||
)
|
||||
terminate( -1 ) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
-- absolute path of source
|
||||
@ -2200,7 +2208,7 @@ local Syncs = ( function( )
|
||||
'Cannot access source directory: ',
|
||||
config.source
|
||||
)
|
||||
terminate( -1 ) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
config._source = config.source
|
||||
@ -2222,7 +2230,7 @@ local Syncs = ( function( )
|
||||
': no actions specified, use e.g. "config = default.rsync".'
|
||||
)
|
||||
|
||||
terminate( -1 ) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
-- loads a default value for an option if not existent
|
||||
@ -2265,7 +2273,7 @@ local Syncs = ( function( )
|
||||
'" unknown.'
|
||||
)
|
||||
|
||||
terminate( -1 ) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
--- creates the new sync
|
||||
@ -3257,7 +3265,7 @@ function runner.callError( message )
|
||||
local info = debug.getinfo( level, 'Sl' )
|
||||
|
||||
if not info then
|
||||
terminate( -1 ) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
log(
|
||||
@ -3403,7 +3411,7 @@ SEE:
|
||||
-- -monitor NAME Uses operating systems event montior NAME
|
||||
-- (inotify/fanotify/fsevents)
|
||||
|
||||
os.exit(-1) -- ERRNO
|
||||
os.exit( -1 )
|
||||
end
|
||||
|
||||
|
||||
@ -3427,12 +3435,15 @@ function runner.configure( args, monitors )
|
||||
-- a list of all valid options
|
||||
--
|
||||
-- first paramter is the number of parameters an option takes
|
||||
-- if < 0 the function checks existance -- TODO what?
|
||||
-- if < 0 the called function has to check the presence of
|
||||
-- optional arguments.
|
||||
--
|
||||
-- second paramter is the function to call
|
||||
--
|
||||
local options = {
|
||||
|
||||
-- log is handled by core already.
|
||||
|
||||
delay =
|
||||
{
|
||||
1,
|
||||
@ -3472,8 +3483,10 @@ function runner.configure( args, monitors )
|
||||
for _, v in ipairs(Monitors.list) do
|
||||
io.stdout:write(' ',v,'\n')
|
||||
end
|
||||
io.stdout:write('\n');
|
||||
lsyncd.terminate(-1); -- ERRNO
|
||||
|
||||
io.stdout:write('\n')
|
||||
|
||||
lsyncd.terminate(-1)
|
||||
else
|
||||
clSettings.monitor = monitor
|
||||
end
|
||||
@ -3543,9 +3556,10 @@ function runner.configure( args, monitors )
|
||||
}
|
||||
|
||||
-- non-opts is filled with all args that were no part dash options
|
||||
|
||||
local nonopts = { }
|
||||
local i =
|
||||
1
|
||||
|
||||
local i = 1
|
||||
while i <= #args do
|
||||
|
||||
local a = args[ i ]
|
||||
@ -3562,16 +3576,21 @@ function runner.configure( args, monitors )
|
||||
local o = options[ a ]
|
||||
|
||||
if not o then
|
||||
log('Error','unknown option command line option ', args[i])
|
||||
os.exit(-1) -- ERRNO
|
||||
log(
|
||||
'Error',
|
||||
'unknown option command line option ',
|
||||
args[i]
|
||||
)
|
||||
os.exit( -1 )
|
||||
end
|
||||
|
||||
if o[ 1 ] >= 0 and i + o[ 1 ] > #args then
|
||||
log( 'Error', a ,' needs ', o[ 1 ],' arguments' )
|
||||
os.exit(-1) -- ERRNO
|
||||
os.exit( -1 )
|
||||
elseif o[1] < 0 then
|
||||
o[ 1 ] = -o[ 1 ]
|
||||
end
|
||||
|
||||
if o[ 2 ] then
|
||||
if o[ 1 ] == 0 then
|
||||
o[ 2 ]( )
|
||||
@ -3586,33 +3605,53 @@ function runner.configure( args, monitors )
|
||||
i = i + o[1]
|
||||
end
|
||||
i = i + 1
|
||||
|
||||
end
|
||||
|
||||
if clSettings.syncs then
|
||||
|
||||
if #nonopts ~= 0 then
|
||||
log('Error', 'There cannot be command line default syncs with a config file.')
|
||||
os.exit(-1) -- ERRNO
|
||||
log(
|
||||
'Error',
|
||||
'There cannot be command line syncs and config file together.'
|
||||
)
|
||||
os.exit( -1 )
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if #nonopts == 0 then
|
||||
|
||||
runner.help( args[ 0 ] )
|
||||
|
||||
elseif #nonopts == 1 then
|
||||
|
||||
return nonopts[ 1 ]
|
||||
|
||||
else
|
||||
log('Error', 'There can only be one config file in command line.')
|
||||
os.exit(-1) -- ERRNO
|
||||
|
||||
-- TODO make this possible
|
||||
log(
|
||||
'Error',
|
||||
'There can only be one config file in command line.'
|
||||
)
|
||||
os.exit( -1 )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
----
|
||||
--
|
||||
-- Called from core on init or restart after user configuration.
|
||||
--
|
||||
-- @firstTime true the first time Lsyncd startup, false on resets
|
||||
-- due to HUP signal or monitor queue OVERFLOW.
|
||||
-- firstTime:
|
||||
-- true when Lsyncd startups the first time,
|
||||
-- false on resets, due to HUP signal or monitor queue overflow.
|
||||
--
|
||||
function runner.initialize( firstTime )
|
||||
|
||||
-- creates settings if user didnt
|
||||
settings = settings or {}
|
||||
|
||||
@ -3621,64 +3660,95 @@ function runner.initialize(firstTime)
|
||||
|
||||
-- copies simple settings with numeric keys to 'key=true' settings.
|
||||
for k, v in ipairs( settings ) do
|
||||
|
||||
if settings[ v ] then
|
||||
log('Error', 'Double setting "'..v..'"')
|
||||
os.exit(-1) -- ERRNO
|
||||
log(
|
||||
'Error',
|
||||
'Double setting "' .. v.. '"'
|
||||
)
|
||||
os.exit( -1 )
|
||||
end
|
||||
|
||||
settings[ v ]= true
|
||||
end
|
||||
|
||||
-- all command line settings overwrite config file settings
|
||||
|
||||
for k, v in pairs( clSettings ) do
|
||||
|
||||
if k ~= 'syncs' then
|
||||
settings[ k ] = v
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- implicitly force insist to be true on Lsyncd resets.
|
||||
-- implicitly force 'insist' on Lsyncd resets.
|
||||
if not firstTime then
|
||||
settings.insist = true
|
||||
end
|
||||
|
||||
-- adds syncs specified by command line.
|
||||
if clSettings.syncs then
|
||||
|
||||
for _, s in ipairs( clSettings.syncs ) do
|
||||
|
||||
if s[1] == 'rsync' then
|
||||
sync{default.rsync, source=s[2], target=s[3]}
|
||||
sync{
|
||||
default.rsync,
|
||||
source = s[ 2 ],
|
||||
target = s[ 3 ]
|
||||
}
|
||||
elseif s[1] == 'rsyncssh' then
|
||||
sync{default.rsyncssh, source=s[2], host=s[3], targetdir=s[4]}
|
||||
sync{
|
||||
default.rsyncssh,
|
||||
source = s[ 2 ],
|
||||
host = s[ 3 ],
|
||||
targetdir=s[ 4 ]
|
||||
}
|
||||
elseif s[1] == 'direct' then
|
||||
sync{ default.direct, source=s[2], target=s[3]}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if settings.nodaemon then
|
||||
lsyncd.configure('nodaemon')
|
||||
end
|
||||
|
||||
if settings.logfile then
|
||||
lsyncd.configure('logfile', settings.logfile)
|
||||
end
|
||||
|
||||
if settings.logident then
|
||||
lsyncd.configure('logident', settings.logident)
|
||||
end
|
||||
|
||||
if settings.logfacility then
|
||||
lsyncd.configure('logfacility', settings.logfacility)
|
||||
end
|
||||
|
||||
if settings.pidfile then
|
||||
lsyncd.configure('pidfile', settings.pidfile)
|
||||
end
|
||||
|
||||
-----
|
||||
-- transfers some defaults to settings
|
||||
--
|
||||
-- Transfers some defaults to settings
|
||||
--
|
||||
if settings.statusInterval == nil then
|
||||
settings.statusInterval = default.statusInterval
|
||||
end
|
||||
|
||||
-- makes sure the user gave Lsyncd anything to do
|
||||
if Syncs.size() == 0 then
|
||||
log('Error', 'Nothing to watch!')
|
||||
os.exit(-1) -- ERRNO
|
||||
|
||||
log(
|
||||
'Error',
|
||||
'Nothing to watch!'
|
||||
)
|
||||
|
||||
os.exit( -1 )
|
||||
end
|
||||
|
||||
-- from now on use logging as configured instead of stdout/err.
|
||||
@ -3686,8 +3756,12 @@ function runner.initialize(firstTime)
|
||||
lsyncd.configure( 'running' );
|
||||
|
||||
local ufuncs = {
|
||||
'onAttrib', 'onCreate', 'onDelete',
|
||||
'onModify', 'onMove', 'onStartup',
|
||||
'onAttrib',
|
||||
'onCreate',
|
||||
'onDelete',
|
||||
'onModify',
|
||||
'onMove',
|
||||
'onStartup',
|
||||
}
|
||||
|
||||
-- translates layer 3 scripts
|
||||
@ -3709,241 +3783,359 @@ function runner.initialize(firstTime)
|
||||
elseif s.config.monitor == 'fsevents' then
|
||||
Fsevents.addSync( s, s.source )
|
||||
else
|
||||
error('sync '..s.config.name..' has no known event monitor interface.')
|
||||
error(
|
||||
'sync ' ..
|
||||
s.config.name ..
|
||||
' has no known event monitor interface.'
|
||||
)
|
||||
end
|
||||
-- if the sync has an init function, stacks an init delay
|
||||
-- that will cause the init function to be called.
|
||||
|
||||
-- if the sync has an init function, the init delay
|
||||
-- is stacked which causes the init function to be called.
|
||||
if s.config.init then
|
||||
s:addInitDelay( )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
----
|
||||
-- Called by core to query soonest alarm.
|
||||
--
|
||||
-- Called by core to query the soonest alarm.
|
||||
--
|
||||
-- @return false ... no alarm, core can in untimed sleep, or
|
||||
-- true ... immediate action
|
||||
-- times ... the alarm time (only read if number is 1)
|
||||
--
|
||||
function runner.getAlarm( )
|
||||
|
||||
if lsyncdStatus ~= 'run' then
|
||||
return false
|
||||
end
|
||||
|
||||
local alarm = false
|
||||
----
|
||||
-- checks if current nearest alarm or a is earlier
|
||||
|
||||
--
|
||||
-- Checks if 'a' is sooner than the 'alarm' up-value.
|
||||
--
|
||||
local function checkAlarm( a )
|
||||
|
||||
if a == nil then
|
||||
error('got nil alarm')
|
||||
end
|
||||
|
||||
if alarm == true or not a then
|
||||
-- already immediate or no new alarm
|
||||
-- 'alarm' is already immediate or
|
||||
-- a not a new alarm
|
||||
return
|
||||
end
|
||||
-- returns the ealier time
|
||||
|
||||
-- sets 'alarm' to a if a is sooner
|
||||
if not alarm or a < alarm then
|
||||
alarm = a
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- checks all syncs for their earliest alarm
|
||||
--
|
||||
-- checks all syncs for their earliest alarm,
|
||||
-- but only if the global process limit is not yet reached.
|
||||
if not settings.maxProcesses or processCount < settings.maxProcesses then
|
||||
--
|
||||
if
|
||||
not settings.maxProcesses or
|
||||
processCount < settings.maxProcesses
|
||||
then
|
||||
for _, s in Syncs.iwalk( ) do
|
||||
checkAlarm( s:getAlarm ( ))
|
||||
end
|
||||
else
|
||||
log('Alarm', 'at global process limit.')
|
||||
log(
|
||||
'Alarm',
|
||||
'at global process limit.'
|
||||
)
|
||||
end
|
||||
|
||||
-- checks if a statusfile write has been delayed
|
||||
checkAlarm( StatusFile.getAlarm( ) )
|
||||
|
||||
-- checks for an userAlarm
|
||||
checkAlarm( UserAlarms.getAlarm( ) )
|
||||
|
||||
log('Alarm', 'runner.getAlarm returns: ',alarm)
|
||||
log(
|
||||
'Alarm',
|
||||
'runner.getAlarm returns: ',
|
||||
alarm
|
||||
)
|
||||
|
||||
return alarm
|
||||
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
-- Called when an inotify event arrived.
|
||||
-- Simply forwards it directly to the object.
|
||||
--
|
||||
-- Called when an file system monitor events arrive
|
||||
--
|
||||
runner.inotifyEvent = Inotify.event
|
||||
runner.fsEventsEvent = Fsevents.event
|
||||
|
||||
-----
|
||||
--
|
||||
-- Collector for every child process that finished in startup phase
|
||||
--
|
||||
-- Parameters are pid and exitcode of child process
|
||||
--
|
||||
-- Can return either a new pid if one other child process
|
||||
-- has been spawned as replacement (e.g. retry) or 0 if
|
||||
-- finished/ok.
|
||||
--
|
||||
function runner.collector(pid, exitcode)
|
||||
function runner.collector(
|
||||
pid, -- pid of the child process
|
||||
exitcode -- exitcode of the child process
|
||||
)
|
||||
if exitcode ~= 0 then
|
||||
log('Error', 'Startup process',pid,' failed')
|
||||
terminate(-1) -- ERRNO
|
||||
terminate( -1 )
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
-----
|
||||
--
|
||||
-- Called by core when an overflow happened.
|
||||
--
|
||||
function runner.overflow( )
|
||||
log('Normal', '--- OVERFLOW in event queue ---')
|
||||
|
||||
log(
|
||||
'Normal',
|
||||
'--- OVERFLOW in event queue ---'
|
||||
)
|
||||
|
||||
lsyncdStatus = 'fade'
|
||||
|
||||
end
|
||||
|
||||
-----
|
||||
--
|
||||
-- Called by core on a hup signal.
|
||||
--
|
||||
function runner.hup( )
|
||||
log('Normal', '--- HUP signal, resetting ---')
|
||||
|
||||
log(
|
||||
'Normal',
|
||||
'--- HUP signal, resetting ---'
|
||||
)
|
||||
|
||||
lsyncdStatus = 'fade'
|
||||
|
||||
end
|
||||
|
||||
-----
|
||||
--
|
||||
-- Called by core on a term signal.
|
||||
--
|
||||
function runner.term( )
|
||||
log('Normal', '--- TERM signal, fading ---')
|
||||
|
||||
log(
|
||||
'Normal',
|
||||
'--- TERM signal, fading ---'
|
||||
)
|
||||
|
||||
lsyncdStatus = 'fade'
|
||||
|
||||
end
|
||||
|
||||
--============================================================================
|
||||
-- Lsyncd user interface
|
||||
-- Lsyncd runner's user interface
|
||||
--============================================================================
|
||||
|
||||
-----
|
||||
--
|
||||
-- Main utility to create new observations.
|
||||
-- @returns an Inlet to that sync.
|
||||
--
|
||||
-- Returns an Inlet to that sync.
|
||||
--
|
||||
function sync( opts )
|
||||
|
||||
if lsyncdStatus ~= 'init' then
|
||||
error('Sync can only be created during initialization.', 2)
|
||||
error(
|
||||
'Sync can only be created during initialization.',
|
||||
2
|
||||
)
|
||||
end
|
||||
|
||||
return Syncs.add( opts ).inlet
|
||||
|
||||
end
|
||||
|
||||
|
||||
-----
|
||||
--
|
||||
-- Spawns a new child process.
|
||||
--
|
||||
-- @param agent the reason why a process is spawned.
|
||||
-- normally this is a delay/event of a sync.
|
||||
function spawn(
|
||||
agent, -- the reason why a process is spawned.
|
||||
-- a delay or delay list for a sync
|
||||
-- it will mark the related files as blocked.
|
||||
-- @param binary binary to call
|
||||
-- @param ... arguments
|
||||
--
|
||||
function spawn(agent, binary, ...)
|
||||
if agent == nil or type(agent) ~= 'table' then
|
||||
error('spawning with an invalid agent', 2)
|
||||
binary, -- binary to call
|
||||
... -- arguments
|
||||
)
|
||||
if
|
||||
agent == nil or
|
||||
type( agent ) ~= 'table'
|
||||
then
|
||||
error(
|
||||
'spawning with an invalid agent',
|
||||
2
|
||||
)
|
||||
end
|
||||
|
||||
if lsyncdStatus == 'fade' then
|
||||
log('Normal', 'ignored process spawning while fading')
|
||||
log(
|
||||
'Normal',
|
||||
'ignored process spawning while fading'
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
if type( binary ) ~= 'string' then
|
||||
error('calling spawn(agent, binary, ...), binary is not a string', 2)
|
||||
error(
|
||||
'calling spawn(agent, binary, ...): binary is not a string',
|
||||
2
|
||||
)
|
||||
end
|
||||
|
||||
local dol = InletFactory.getDelayOrList( agent )
|
||||
if not dol then error('spawning with an unknown agent', 2) end
|
||||
|
||||
-- checks if spawn is called on already active event
|
||||
if not dol then
|
||||
error(
|
||||
'spawning with an unknown agent',
|
||||
2
|
||||
)
|
||||
end
|
||||
|
||||
--
|
||||
-- checks if a spawn is called on an already active event
|
||||
--
|
||||
if dol.status then
|
||||
|
||||
-- is an event
|
||||
|
||||
if dol.status ~= 'wait' then
|
||||
error('spawn() called on an non-waiting event', 2)
|
||||
end
|
||||
else -- is a list
|
||||
|
||||
else
|
||||
-- is a list
|
||||
|
||||
for _, d in ipairs(dol) do
|
||||
if d.status ~= 'wait' and d.status ~= 'block' then
|
||||
error('spawn() called on an non-waiting event list', 2)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- tries to spawn the process
|
||||
--
|
||||
local pid = lsyncd.exec( binary, ... )
|
||||
|
||||
if pid and pid > 0 then
|
||||
|
||||
processCount = processCount + 1
|
||||
if settings.maxProcesses and processCount > settings.maxProcesses then
|
||||
if
|
||||
settings.maxProcesses and
|
||||
processCount > settings.maxProcesses
|
||||
then
|
||||
error( 'Spawned too much processes!' )
|
||||
end
|
||||
|
||||
local sync = InletFactory.getSync( agent )
|
||||
|
||||
-- delay or list
|
||||
if dol.status then
|
||||
|
||||
-- is a delay
|
||||
dol.status = 'active'
|
||||
sync.processes[ pid ] = dol
|
||||
|
||||
else
|
||||
|
||||
-- is a list
|
||||
for _, d in ipairs( dol ) do
|
||||
d.status = 'active'
|
||||
end
|
||||
sync.processes[ pid ] = dol
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-----
|
||||
--
|
||||
-- Spawns a child process using the default shell.
|
||||
--
|
||||
function spawnShell(agent, command, ...)
|
||||
return spawn(agent, '/bin/sh', '-c', command, '/bin/sh', ...)
|
||||
function spawnShell(
|
||||
agent, -- the delay(list) to spawn the command for
|
||||
command, -- the shell command
|
||||
... -- additonal arguments
|
||||
)
|
||||
return spawn(
|
||||
agent,
|
||||
'/bin/sh',
|
||||
'-c',
|
||||
command,
|
||||
'/bin/sh',
|
||||
...
|
||||
)
|
||||
end
|
||||
|
||||
-----
|
||||
-- Observes a filedescriptor
|
||||
--
|
||||
function observefd(fd, ready, writey)
|
||||
return lsyncd.observe_fd(fd, ready, writey)
|
||||
function observefd(
|
||||
fd, -- file descriptor
|
||||
ready, -- called when fd is ready to be read
|
||||
writey -- called when fd is ready to be written
|
||||
)
|
||||
return lsyncd.observe_fd(
|
||||
fd,
|
||||
ready,
|
||||
writey
|
||||
)
|
||||
end
|
||||
|
||||
-----
|
||||
-- Nonobserves a filedescriptor
|
||||
--
|
||||
function nonobservefd(fd)
|
||||
-- Stops observeing a filedescriptor
|
||||
--
|
||||
function nonobservefd(
|
||||
fd -- file descriptor
|
||||
)
|
||||
return lsyncd.nonobserve_fd( fd )
|
||||
end
|
||||
|
||||
-----
|
||||
--
|
||||
-- Calls func at timestamp.
|
||||
--
|
||||
-- Use now() to receive current timestamp
|
||||
-- add seconds with '+' to it)
|
||||
-- add seconds with '+' to it
|
||||
--
|
||||
alarm = UserAlarms.alarm
|
||||
|
||||
-----
|
||||
--
|
||||
-- Comfort routine also for user.
|
||||
-- Returns true if 'String' starts with 'Start'
|
||||
--
|
||||
function string.starts( String, Start )
|
||||
|
||||
return string.sub( String, 1, #Start )==Start
|
||||
|
||||
end
|
||||
|
||||
-----
|
||||
--
|
||||
-- Comfort routine also for user.
|
||||
-- Returns true if 'String' ends with 'End'
|
||||
--
|
||||
function string.ends( String, End )
|
||||
|
||||
return End == '' or string.sub( String, -#End ) == End
|
||||
|
||||
end
|
||||
|
||||
-----
|
||||
-- provides a default empty settings table.
|
||||
--
|
||||
-- Provides a default empty settings table.
|
||||
--
|
||||
settings = { }
|
||||
|
||||
-----
|
||||
--
|
||||
-- Returns the core the runners function interface.
|
||||
--
|
||||
return runner
|
||||
|
Loading…
Reference in New Issue
Block a user