ruby-livesync 1.0.0.beta3 → 1.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b752ff64938cd1e8c5abd600ce03aebc501b0a45088aea45d73f14f3cf1bd8f
4
- data.tar.gz: a68ed7c8374b0e380d8dc183c222d42c904edbecaf4b198fc82a89e960e3419d
3
+ metadata.gz: 1e77356b7dfd5070935875d4842a16129c5d1eeaaec1e049d2b4e4824032a2c0
4
+ data.tar.gz: f8350e318d1f3e31dc5925981c1526b74d404795c4300419a2db489ff38e0f2a
5
5
  SHA512:
6
- metadata.gz: 9e1e8e35696105846bde4cd4592f70bce67007e0cd570299993587a276845b4366cc71d91608637ae8745ded4c2b61ac247825190b9dbba87ff4d90e11ada15d
7
- data.tar.gz: 930d1b2b01093cb90e06ed60316822b0c36d2e17f20089b0d0c30b54faeb358a65d77973c0ccfe30bc1d39960e28fb2d4e400cfd4844128952a5c5ada4ac3ff6
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,6 +22,11 @@ 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
32
  raise "#{ctx}: source isn't a directory" unless File.directory? source
@@ -32,14 +34,14 @@ module LiveSync
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,46 +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
60
  watch source
62
- @rsync.initial
63
- schedule
61
+ target.initial
64
62
  sleep 1.day while true
65
63
  end
66
64
  end
67
65
 
68
- def track event
69
- path = event.absolute_name
70
- watch path if File.directory?(path) and :create.in? event.flags
71
- @to_sync << Pathname.new(path).relative_path_from(@pathname).to_s
72
- end
73
-
74
66
  def watch dir
75
- @watcher.dir_rwatch dir, &method(:track)
76
- end
77
-
78
- def schedule
79
- @scheduler.in "#{delay}s", &method(:check)
67
+ @watcher.watch dir, *modes, excludes: excludes, delay: delay, &method(:sync)
80
68
  end
81
69
 
82
- def check
83
- return if @rsync.running?
84
- @watcher.process # calls #track
85
- return if @to_sync.blank?
86
- @rsync.partial @to_sync
87
- @to_sync.clear
88
- ensure
89
- schedule
70
+ def sync paths
71
+ return if target.running?
72
+ target.partial paths
90
73
  end
91
74
 
92
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.beta3'
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.beta3
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