ruby-livesync 1.0.0.beta2 → 1.0.0.beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d19adaa07cc52746ac91f99dc954b5b85c3d1150b41ffb4e789c453efe404ae
4
- data.tar.gz: bf4db87f65060754f52063a41dfc27094027fd8165e4b722f051e6af069dd6cf
3
+ metadata.gz: 1e77356b7dfd5070935875d4842a16129c5d1eeaaec1e049d2b4e4824032a2c0
4
+ data.tar.gz: f8350e318d1f3e31dc5925981c1526b74d404795c4300419a2db489ff38e0f2a
5
5
  SHA512:
6
- metadata.gz: 4caca9a0bb7a879d9133d0aadf74768f2252866f6b5729eb45935ee5d975bb7029a77a40d2e9ada50026ee196bf2ca1a54e5aa4169ca0e87892670a8dc818587
7
- data.tar.gz: 50b8a7101b60a5f4b29906f38b92a1cfc1671ebac8cd7aba1fe78ae879cda7d4f2a441ec248e68a7201959f356e12dc0e5583c8cee6e9ea234ba8290b0385e7a
6
+ metadata.gz: 9989027e61b51d31e4248e71c7d24e3d1a8c9cfaf74ab532cd99fcc6f25ae7d9e23c12790cc31a57e306395213c846e132e3cdc24c6d14d548f74d525860515d
7
+ data.tar.gz: 43ac4cf5d5ff1cc2926bb13ba60f4efbafa07fd54d940d8bdb55cbd183b6a608c6d644a4a7173c2ebdf1d490534eedd37e1940ef9854b98b16201d3461be5009
data/config/sample.rb CHANGED
@@ -3,15 +3,27 @@
3
3
  sync '4tb' do
4
4
  enabled = false
5
5
 
6
+ # watchers available:
7
+ # - :rb (default)
8
+ # - :py_inotify
9
+ # - :cmd (inotifywait)
10
+ # - :py_watchdog
11
+ #
12
+ watcher = :rb
13
+
6
14
  # fork to user below, usually associated with private keys
7
15
  user = :root
8
16
 
9
17
  delay = 5
10
18
 
11
- source = '/mnt/4tb/'
12
- target = 'root@bhavapower:/mnt/extensor/4tb'
19
+ # event list from inotify
20
+ # full list at https://manpages.ubuntu.com/manpages/latest/en/man1/inotifywait.1.html#events
21
+ modes = %i[create modify]
13
22
 
14
- rsync.opts = '-ax --partial' # default
23
+ source = '/mnt/4tb/'
24
+ target rsync: 'root@bhavapower:/mnt/extensor/4tb' do
25
+ opts = '-ax --partial' # default
26
+ end
15
27
 
16
28
  # possible values are: true, false, :initial, :watched
17
29
  delete = true
@@ -0,0 +1,56 @@
1
+ module LiveSync
2
+ class CmdWatcher < Watcher
3
+
4
+ class_attribute :base_cmd
5
+ self.base_cmd = 'bash -s'
6
+
7
+ class_attribute :script
8
+ self.script = <<-HEREDOC
9
+ tp=$(mktemp -u)
10
+ mkfifo $tp
11
+ inotifywait %{opts} -m -e %{events} --format "%%e %%w%%f" %{path} %{excludes} > $tp 2>/dev/null &
12
+ ipid=$!
13
+ trap "kill $ipid; rm -f $tp; exit" INT TERM EXIT
14
+ while true; do
15
+ timeout %{delay} cat < $tp | sort | uniq
16
+ done
17
+ HEREDOC
18
+
19
+ def watch path, *modes, **params
20
+ modes = DEFAULT_MODES if modes.blank?
21
+ script = self.script % parsed_params(path, *modes, **params)
22
+ stdin, stdout, stderr, @wait_thr = Open3.popen3 base_cmd
23
+ stdin.write script
24
+ stdin.close
25
+
26
+ Thread.new do
27
+ stdout.sync = true
28
+ lines = stdout.each_line.each do |line|
29
+ file,events = parse line
30
+ yield [OpenStruct.new(absolute_name: file, flags: events)]
31
+ end
32
+ end
33
+ Thread.new do
34
+ STDERR.puts stderr.read
35
+ end
36
+ end
37
+
38
+ def parsed_params path, *modes, recursive: true, delay: 1, excludes: [], **params
39
+ opts = '-r' if recursive
40
+ {
41
+ path: path,
42
+ opts: opts,
43
+ events: modes.join(','),
44
+ delay: delay,
45
+ excludes: excludes.map{ |e| "'@#{e}'" }.join(' '),
46
+ }
47
+ end
48
+
49
+ def parse line
50
+ events,file = line.split ' ', 2
51
+ events = events.split(',').map(&:downcase).map(&:to_sym)
52
+ [file.chomp, events]
53
+ end
54
+
55
+ end
56
+ end
@@ -22,8 +22,7 @@ module LiveSync
22
22
  end
23
23
 
24
24
  def sync name_or_path, &block
25
- s = Sync.new name_or_path
26
- s.dsl_apply(&block)
25
+ s = Sync.new name_or_path, &block
27
26
  @syncs[s.user] << s
28
27
  end
29
28
 
@@ -10,24 +10,27 @@ module LiveSync
10
10
  class_attribute :attrs
11
11
  self.attrs = []
12
12
 
13
- def self.dsl attr, default: nil, enum: nil, type: nil, &block
13
+ def self.dsl attr, default: nil, enum: nil,
14
+ type: nil, skip_set: false, &block
14
15
  self.attrs << attr
15
- define_method attr do |sv=nil|
16
+
17
+ define_method attr do |sv=nil, opts={}, &ablock|
18
+ sv = default if opts[:init]
16
19
  (v = instance_variable_get("@#{attr}"); return(if v.nil? then default else v end)) if sv.nil?
17
20
 
18
- raise "#{ctx}/#{attr}: incorrect type" if type and !sv.is_a? type
21
+ raise "#{ctx}/#{attr}: incorrect type of #{sv.inspect}" if type and !sv.is_a? type
19
22
  raise "#{ctx}/#{attr}: value not one of following #{enum}" if enum and !sv.in? enum
20
23
 
21
- instance_variable_set "@#{attr}", sv
22
- instance_exec sv, &block if block
24
+ instance_variable_set "@#{attr}", sv unless skip_set
25
+ instance_exec sv, ablock, &block if block
23
26
  end
24
27
  end
25
28
 
26
29
  def dsl_apply &block
27
30
  if b = binding and bs = block.source.match(/do(.+)end$/m)&.captures&.first
28
31
  b.eval bs
29
- attrs.each do |a| # read local variables
30
- next unless a.in? b.local_variables
32
+ attrs.each do |a|
33
+ next send a, nil, {init: true} unless a.in? b.local_variables
31
34
  send a, b.local_variable_get(a)
32
35
  end
33
36
  else
@@ -0,0 +1,45 @@
1
+ import pyinotify
2
+ import os
3
+ import time
4
+
5
+ class EventHandler(pyinotify.ProcessEvent):
6
+ def my_init(self, excludes, recursive, mask):
7
+ self.excludes = excludes
8
+ self.recursive = recursive
9
+ self.mask = mask
10
+ self.events = set()
11
+
12
+ def process_default(self, event):
13
+ full_path = event.pathname
14
+ if not any(exclude in full_path for exclude in self.excludes):
15
+ event_desc = event.maskname
16
+ self.events.add((event_desc, full_path))
17
+
18
+ def print_events(self):
19
+ if self.events:
20
+ for event_desc, full_path in self.events:
21
+ print(f"{event_desc} {full_path}", flush=True)
22
+ self.events.clear()
23
+
24
+ def add_watch(self, path):
25
+ wm.add_watch(path, self.mask, rec=self.recursive, auto_add=True)
26
+
27
+ excludes = [%{excludes}]
28
+ recursive = %{recursive}
29
+ event_mask = pyinotify.IN_CREATE | pyinotify.IN_MODIFY | pyinotify.IN_MOVED_TO | pyinotify.IN_DELETE # Event mask
30
+
31
+ wm = pyinotify.WatchManager()
32
+ handler = EventHandler(excludes=excludes, recursive=recursive, mask=event_mask)
33
+ notifier = pyinotify.Notifier(wm, handler)
34
+ handler.add_watch('%{path}')
35
+
36
+ try:
37
+ while True:
38
+ notifier.process_events()
39
+ if notifier.check_events():
40
+ notifier.read_events()
41
+ handler.print_events()
42
+ time.sleep(%{delay})
43
+ except KeyboardInterrupt:
44
+ notifier.stop()
45
+
@@ -0,0 +1,52 @@
1
+ from watchdog.observers import Observer
2
+ from watchdog.events import FileSystemEventHandler
3
+ import time
4
+
5
+ class MyEventHandler(FileSystemEventHandler):
6
+ def __init__(self, observer, excludes):
7
+ self.observer = observer
8
+ self.excludes = excludes
9
+ self.events = set()
10
+
11
+ def handle_event(self, event):
12
+ if not any(exclusion in event.src_path for exclusion in self.excludes):
13
+ self.events.add((event.event_type, event.src_path))
14
+ if event.event_type == 'created' and os.path.isdir(event.src_path):
15
+ self.schedule_directory(event.src_path)
16
+
17
+ def on_modified(self, event):
18
+ self.handle_event(event)
19
+
20
+ def on_created(self, event):
21
+ self.handle_event(event)
22
+
23
+ def on_deleted(self, event):
24
+ self.handle_event(event)
25
+
26
+ def on_moved(self, event):
27
+ self.handle_event(event)
28
+
29
+ def print_events(self):
30
+ if self.events:
31
+ for event_type, src_path in self.events:
32
+ print(f"{event_type} {src_path}", flush=True)
33
+ self.events.clear()
34
+
35
+ def schedule_directory(self, path):
36
+ self.observer.schedule(self, path, recursive=%{recursive})
37
+
38
+ path = "%{path}"
39
+ excludes = [%{excludes}]
40
+ observer = Observer()
41
+ event_handler = MyEventHandler(observer, excludes)
42
+ event_handler.schedule_directory(path)
43
+
44
+ observer.start()
45
+ try:
46
+ while True:
47
+ time.sleep(%{delay})
48
+ event_handler.print_events()
49
+ except KeyboardInterrupt:
50
+ observer.stop()
51
+ observer.join()
52
+
@@ -0,0 +1,19 @@
1
+ module LiveSync
2
+ class PyInotifyWatcher < CmdWatcher
3
+
4
+ self.base_cmd = 'python'
5
+
6
+ self.script = File.read "#{File.dirname __FILE__}/py/inotify.py"
7
+
8
+ def parsed_params path, *modes, recursive: true, delay: 1, excludes: [], **params
9
+ {
10
+ path: path,
11
+ recursive: if recursive then 'True' else 'False' end,
12
+ events: modes.join(','),
13
+ delay: delay,
14
+ excludes: excludes.map{ |e| "'#{e}'" }.join(','),
15
+ }
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module LiveSync
2
+ class PyWatchdogWatcher < CmdWatcher
3
+
4
+ self.base_cmd = 'python'
5
+
6
+ self.script = File.read "#{File.dirname __FILE__}/py/watchdog.py"
7
+
8
+ def parsed_params path, *modes, recursive: true, delay: 1, excludes: [], **params
9
+ {
10
+ path: path,
11
+ recursive: if recursive then 'True' else 'False' end,
12
+ events: modes.join(','),
13
+ delay: delay,
14
+ excludes: excludes.map{ |e| "'#{e}'" }.join(','),
15
+ }
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,88 @@
1
+ module LiveSync
2
+ class RbWatcher < Watcher
3
+
4
+ def watch path, *modes, excludes: [], samefs: true, delay: 1, recursive: true, **params, &block
5
+ raise "#{path}: not a directory" unless File.directory? path
6
+ modes = DEFAULT_MODES if modes.blank?
7
+ modes << :delete if sync&.delete&.in? [true, :watched]
8
+
9
+ tracker = Tracker.new path, delay, &block
10
+ rtgts = glob path, recursive: recursive, excludes: excludes
11
+ track(path, rtgts, *modes,
12
+ delay: 1,
13
+ tracker: tracker,
14
+ recursive: recursive,
15
+ excludes: excludes,
16
+ samefs: samefs,
17
+ )
18
+ tracker.timeout_check
19
+
20
+ self
21
+ end
22
+
23
+ protected
24
+
25
+ class Tracker
26
+ def initialize path, delay, &block
27
+ @delay = delay
28
+ @block = block
29
+ @to_sync = Set.new
30
+ @notifier = INotify::Notifier.new
31
+ @pathname = Pathname.new path
32
+ end
33
+
34
+ def watch *args, &block
35
+ @notifier.watch *args, &block
36
+ end
37
+
38
+ def track event
39
+ @to_sync << Pathname.new(event.absolute_name).relative_path_from(@pathname).to_s
40
+ end
41
+
42
+ def check
43
+ @notifier.process # calls track
44
+ @block.call @to_sync
45
+ @to_sync.clear
46
+ ensure
47
+ timeout_check
48
+ end
49
+
50
+ def timeout_check
51
+ Thread.new{ sleep @delay; check }
52
+ end
53
+ end
54
+
55
+ def track path, rtgts, *modes, tracker:, **opts
56
+ rtgts.each do |rt|
57
+ t = "#{path}/#{rt}"
58
+ tracker.watch t, *modes do |event|
59
+ tracker.track event
60
+ et = event.absolute_name
61
+ next unless opts[:recursive] and File.directory?(et) and :create.in? event.flags
62
+ track et, glob(et, **opts), *modes, tracker: tracker, **opts
63
+ end
64
+ rescue => e
65
+ Log.warning "watcher: #{t}: skipping due to #{e.class}: #{e.message}"
66
+ end
67
+ end
68
+
69
+ def glob path, recursive: true, samefs: true, excludes: [], **params
70
+ wcard = if recursive then '{.**,**}/' else '' end
71
+ tgts = [path] + Dir.glob("#{path}/#{wcard}")
72
+
73
+ dev = File.stat(path).dev
74
+ tgts.select!{ |t| dev == File.stat(t).dev } if samefs
75
+
76
+ rtgts = tgts.map{ |t| Pathname.new(t).relative_path_from(path).to_s }
77
+ excs = excludes.map{ |e| Regexp.new e } || []
78
+ excs.each do |e|
79
+ next unless mt = rtgts.find{ |rt| e.match rt }
80
+ Log.debug "watcher: skipping #{path}/#{mt} with subdirs"
81
+ rtgts.delete mt
82
+ rtgts.delete_if{ |rt| rt.start_with? mt } if File.directory? "#{path}/#{mt}"
83
+ end
84
+ rtgts
85
+ end
86
+
87
+ end
88
+ end
@@ -1,12 +1,20 @@
1
1
  module LiveSync
2
- class Rsync
2
+ class Rsync < Target
3
3
 
4
- attr_reader :sync
5
- attr_accessor :opts
4
+ dsl :opts, type: String
6
5
 
7
- def initialize sync
8
- @sync = sync
9
- @opts = '-ax --partial'
6
+ attr_reader :ssh
7
+
8
+ def initialize *args, &block
9
+ super
10
+ # add trailing slash in case the dir is the same
11
+ sync.source File.join(sync.source, '') if File.basename(sync.source) == File.basename(@path)
12
+ end
13
+
14
+ def start
15
+ @ssh = Ssh.connect userhost
16
+ sleep 1 and log.warning 'waiting for ssh' while !@ssh.available?
17
+ true
10
18
  end
11
19
 
12
20
  def running?
@@ -31,21 +39,21 @@ module LiveSync
31
39
  protected
32
40
 
33
41
  def run type, *args, loglevel: :debug
34
- cmd = "rsync -e '#{rsh}' #{opts} #{sync.source} #{sync.target} #{args.join ' '}"
42
+ cmd = "rsync -e '#{rsh}' #{opts} #{sync.source} #{dest} #{args.join ' '}"
35
43
  sync.excludes.each{ |e| cmd << " --exclude='#{e}'" }
36
44
 
37
- sync.log.send loglevel, "#{type}: starting with cmd: #{cmd}"
45
+ log.send loglevel, "#{type}: starting with cmd: #{cmd}"
38
46
  stdin, stdout, stderr, @wait_thr = Open3.popen3 cmd
39
47
  yield stdin, stdout, stderr if block_given?
40
48
  Thread.new do
41
49
  Process.wait @wait_thr.pid rescue Errno::ECHILD; nil
42
50
  @wait_thr = nil
43
- sync.log.send loglevel, "#{type}: finished"
51
+ log.send loglevel, "#{type}: finished"
44
52
  end
45
53
  end
46
54
 
47
55
  def rsh
48
- "ssh -o ControlPath=#{sync.ssh.cpath}"
56
+ "ssh -o ControlPath=#{ssh.cpath}"
49
57
  end
50
58
 
51
59
  end
@@ -4,17 +4,14 @@ module LiveSync
4
4
  include DSL
5
5
 
6
6
  attr_reader :name
7
- attr_reader :scheduler
8
7
  attr_reader :log
9
8
  attr_reader :watcher
10
- attr_reader :ssh
11
- attr_reader :rsync
9
+ attr_reader :target
12
10
 
13
- def initialize name = nil
11
+ def initialize name = nil, &block
14
12
  fill_name name
15
13
  source name if File.exist? name
16
- @to_sync = Set.new
17
- @rsync = Rsync.new self
14
+ dsl_apply(&block)
18
15
  end
19
16
 
20
17
  def fill_name name
@@ -25,21 +22,26 @@ module LiveSync
25
22
 
26
23
  dsl :enabled, default: true
27
24
 
25
+ dsl :watcher, skip_set: true, default: :rb do |name|
26
+ klass = :"#{name.to_s.camelize}Watcher"
27
+ @watcher_class = LiveSync.const_get klass
28
+ end
29
+
28
30
  dsl :user, default: :root
29
31
  dsl :source do |source|
30
- raise "#{ctx}: source not found" unless File.exist? source
32
+ raise "#{ctx}: source isn't a directory" unless File.directory? source
31
33
  fill_name source
32
34
  @pathname = Pathname.new source
33
35
  end
34
36
 
35
- dsl :target do |target|
36
- @userhost, @target_path = target.split(':')
37
- raise "#{ctx}: missing target path" unless @target_path
38
- source File.join(@source, '') if File.basename(@source) == File.basename(@target_path)
37
+ dsl :target, skip_set: true do |opts, &block|
38
+ @target = Rsync.new self, opts[:rsync], &block if opts[:rsync]
39
39
  end
40
40
 
41
41
  dsl :delay, default: 5, type: Integer
42
42
 
43
+ dsl :modes, default: %i[create modify], type: Array
44
+
43
45
  dsl :delete, default: false, enum: [true,false] + %i[initial watched]
44
46
 
45
47
  dsl :excludes, default: []
@@ -47,40 +49,27 @@ module LiveSync
47
49
  def start
48
50
  return log.warning('skipping disabled sync') && false unless enabled
49
51
  raise "#{ctx}: missing target" unless @target
50
- @ssh = Ssh.connect @userhost
51
- sleep 1 and log.warning 'waiting for ssh' while !@ssh.available?
52
- true
52
+ target.start
53
53
  end
54
54
 
55
55
  def guard
56
56
  fork do
57
57
  Process.setproctitle "livesync: sync #{ctx}"
58
- @watcher = Watcher.new self
59
- @scheduler = Rufus::Scheduler.new
58
+ @watcher = @watcher_class.new self
60
59
 
61
- @watcher.dir_rwatch source, &method(:track)
62
- @rsync.initial
63
- schedule
60
+ watch source
61
+ target.initial
64
62
  sleep 1.day while true
65
63
  end
66
64
  end
67
65
 
68
- def track event
69
- @to_sync << Pathname.new(event.absolute_name).relative_path_from(@pathname).to_s
70
- end
71
-
72
- def schedule
73
- @scheduler.in "#{delay}s", &method(:check)
66
+ def watch dir
67
+ @watcher.watch dir, *modes, excludes: excludes, delay: delay, &method(:sync)
74
68
  end
75
69
 
76
- def check
77
- return if @rsync.running?
78
- @watcher.process # calls #track
79
- return if @to_sync.blank?
80
- @rsync.partial @to_sync
81
- @to_sync.clear
82
- ensure
83
- schedule
70
+ def sync paths
71
+ return if target.running?
72
+ target.partial paths
84
73
  end
85
74
 
86
75
  protected
@@ -0,0 +1,36 @@
1
+ module LiveSync
2
+ class Target
3
+
4
+ include DSL
5
+
6
+ attr_reader :sync
7
+ delegate :log, to: :sync
8
+
9
+ attr_reader :dest, :path, :userhost
10
+
11
+ def initialize sync, dest, &block
12
+ @sync = sync
13
+ @dest = dest
14
+ @userhost, @path = dest.split ':'
15
+ raise "#{sync.ctx}: missing target path" unless @path
16
+ dsl_apply &block if block
17
+ end
18
+
19
+ def start
20
+ false
21
+ end
22
+
23
+ def running?
24
+ false
25
+ end
26
+
27
+ def initial
28
+ raise 'not implemented'
29
+ end
30
+
31
+ def partial paths
32
+ raise 'not implemented'
33
+ end
34
+
35
+ end
36
+ end
@@ -1,5 +1,5 @@
1
1
  module LiveSync
2
2
 
3
- VERSION = '1.0.0.beta2'
3
+ VERSION = '1.0.0.beta4'
4
4
 
5
5
  end
@@ -1,50 +1,15 @@
1
1
  module LiveSync
2
2
  class Watcher
3
3
 
4
- attr_reader :notifier
5
- delegate_missing_to :notifier
4
+ DEFAULT_MODES = %i[create modify]
6
5
 
7
6
  attr_reader :sync
8
7
 
9
8
  def initialize sync=nil
10
- @sync = sync
11
- @notifier = INotify::Notifier.new
9
+ @sync = sync
12
10
  end
13
11
 
14
- def watch path, *modes
15
- Log.debug "#{path}: watching for #{modes.join ','}"
16
- modes = %i[all_events] if modes.blank?
17
-
18
- notifier.watch path, *modes do |event|
19
- yield event
20
- end
21
- self
22
- end
23
-
24
- def dir_rwatch path, *modes
25
- raise "#{path}: not a directory" unless File.directory? path
26
- modes = %i[create modify] if modes.blank?
27
- modes << :delete if sync&.delete&.in? [true, :watched]
28
-
29
- excs = sync&.excludes.map{ |e| Regexp.new e } || []
30
- tgts = [path] + Dir.glob("#{path}/{.**,**}/")
31
- rtgts = tgts.map{ |t| Pathname.new(t).relative_path_from(path).to_s }
32
- excs.each do |e|
33
- next unless mt = rtgts.find{ |rt| e.match rt }
34
- Log.debug "watcher: skipping #{path}/#{mt} with subdirs"
35
- rtgts.delete mt
36
- rtgts.delete_if{ |rt| rt.start_with? mt } if File.directory? "#{path}/#{mt}"
37
- end
38
-
39
- rtgts.each do |rt|
40
- t = "#{path}/#{rt}"
41
- notifier.watch t, *modes do |event|
42
- yield event
43
- end
44
- rescue => e
45
- Log.warning "watcher: #{t}: skipping due to #{e.class}: #{e.message}"
46
- end
47
- self
12
+ def watch path, *modes, delay: 1, excludes: [], &block
48
13
  end
49
14
 
50
15
  end
@@ -7,8 +7,13 @@ require_relative 'live_sync/dsl'
7
7
  require_relative 'live_sync/log'
8
8
  require_relative 'live_sync/user'
9
9
  require_relative 'live_sync/ssh'
10
+ require_relative 'live_sync/target'
10
11
  require_relative 'live_sync/rsync'
11
12
  require_relative 'live_sync/watcher'
13
+ require_relative 'live_sync/rb_watcher'
14
+ require_relative 'live_sync/cmd_watcher'
15
+ require_relative 'live_sync/py_inotify_watcher'
16
+ require_relative 'live_sync/py_watchdog_watcher'
12
17
  require_relative 'live_sync/sync'
13
18
  require_relative 'live_sync/daemon'
14
19
 
data/lib/ruby-livesync.rb CHANGED
@@ -2,7 +2,6 @@ require 'pry'
2
2
  require 'active_support/all'
3
3
 
4
4
  require 'rb-inotify'
5
- require 'rufus-scheduler'
6
5
 
7
6
  require_relative 'ruby-livesync/live_sync'
8
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-livesync
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta2
4
+ version: 1.0.0.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Braulio Oliveira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-13 00:00:00.000000000 Z
11
+ date: 2024-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: rufus-scheduler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  description:
70
56
  email:
71
57
  - brauliobo@gmail.com
@@ -78,12 +64,19 @@ files:
78
64
  - config/sample.rb
79
65
  - lib/ruby-livesync.rb
80
66
  - lib/ruby-livesync/live_sync.rb
67
+ - lib/ruby-livesync/live_sync/cmd_watcher.rb
81
68
  - lib/ruby-livesync/live_sync/daemon.rb
82
69
  - lib/ruby-livesync/live_sync/dsl.rb
83
70
  - lib/ruby-livesync/live_sync/log.rb
71
+ - lib/ruby-livesync/live_sync/py/inotify.py
72
+ - lib/ruby-livesync/live_sync/py/watchdog.py
73
+ - lib/ruby-livesync/live_sync/py_inotify_watcher.rb
74
+ - lib/ruby-livesync/live_sync/py_watchdog_watcher.rb
75
+ - lib/ruby-livesync/live_sync/rb_watcher.rb
84
76
  - lib/ruby-livesync/live_sync/rsync.rb
85
77
  - lib/ruby-livesync/live_sync/ssh.rb
86
78
  - lib/ruby-livesync/live_sync/sync.rb
79
+ - lib/ruby-livesync/live_sync/target.rb
87
80
  - lib/ruby-livesync/live_sync/user.rb
88
81
  - lib/ruby-livesync/live_sync/version.rb
89
82
  - lib/ruby-livesync/live_sync/watcher.rb
@@ -103,11 +96,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
96
  version: '0'
104
97
  required_rubygems_version: !ruby/object:Gem::Requirement
105
98
  requirements:
106
- - - ">"
99
+ - - ">="
107
100
  - !ruby/object:Gem::Version
108
- version: 1.3.1
101
+ version: '0'
109
102
  requirements: []
110
- rubygems_version: 3.3.25
103
+ rubygems_version: 3.5.3
111
104
  signing_key:
112
105
  specification_version: 4
113
106
  summary: Lightweight and fast live sync daemon