entangler 0.1.1 → 0.1.2

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
  SHA1:
3
- metadata.gz: 490b5a2f8672548a4e3a7d15fbd641291f9456fc
4
- data.tar.gz: 5750ebccf9775aa3971dc7dfe930527ee7803af4
3
+ metadata.gz: e910a8be4617a7df89c5a0d5f94b51617a26deb6
4
+ data.tar.gz: 1d083cf56c15e7f332c703eb36381d31e717b7f6
5
5
  SHA512:
6
- metadata.gz: 6b74a61f4a3dda5e52b8b10fe8f41e92eb9e9266dfa923bfc015b857f68e24757770c620ee6f937da0fc18e2885c2a0a723a2a329febf9871574ab9128dd223e
7
- data.tar.gz: 4df993ced868041b7f96012b425bf2b0a1d569a1d16074a852c63bf4e9d1b96f19b2ffd1ff362af09f00888bb7a8ca55ce9471848db37d19f76b63b56aa4c642
6
+ metadata.gz: 829fd8b9cc788a049e1daab942a3eff9d911351f580b71f276610c0c48b758638698868066ceb39e3bac63a6bebc7e295915d19fd95d7f93e4a66a0bfe057b65
7
+ data.tar.gz: b08f880f5e249658f83b906e3789adf84b999d9922b068dc6eec037aa069475a62434212287f3a3898f56661a1a01c43911eab4c9b70fd6c59a12f153edd92ef
@@ -28,6 +28,23 @@ module Entangler
28
28
  File.exists?(full_path)
29
29
  end
30
30
 
31
+ def export
32
+ raise "Delta file doesn't exist when creaing patched file" unless delta_exists?
33
+ tempfile = Tempfile.new('final_file')
34
+ if File.exists?(full_path)
35
+ LibRubyDiff.patch(full_path, delta_file.path, tempfile.path)
36
+ else
37
+ temp_empty_file = Tempfile.new('empty_file')
38
+ LibRubyDiff.patch(temp_empty_file.path, delta_file.path, tempfile.path)
39
+ end
40
+ tempfile.rewind
41
+ File.open(full_path, 'w'){|f| f.write(tempfile.read)}
42
+ tempfile.close
43
+ tempfile.unlink
44
+ File.utime(File.atime(full_path), @desired_modtime, full_path)
45
+ end
46
+
47
+ private
31
48
  def signature_exists?
32
49
  defined?(@signature_tempfile)
33
50
  end
@@ -79,22 +96,6 @@ module Entangler
79
96
  delta_file.read
80
97
  end
81
98
 
82
- def export
83
- raise "Delta file doesn't exist when creaing patched file" unless delta_exists?
84
- tempfile = Tempfile.new('final_file')
85
- if File.exists?(full_path)
86
- LibRubyDiff.patch(full_path, delta_file.path, tempfile.path)
87
- else
88
- temp_empty_file = Tempfile.new('empty_file')
89
- LibRubyDiff.patch(temp_empty_file.path, delta_file.path, tempfile.path)
90
- end
91
- tempfile.rewind
92
- File.open(full_path, 'w'){|f| f.write(tempfile.read)}
93
- tempfile.close
94
- tempfile.unlink
95
- File.utime(File.atime(full_path), @desired_modtime, full_path)
96
- end
97
-
98
99
  def close_and_unlink_files
99
100
  if signature_exists?
100
101
  @signature_tempfile.close
@@ -0,0 +1,108 @@
1
+ module Entangler
2
+ module Executor
3
+ module Background
4
+ module Base
5
+ protected
6
+ def wait_for_threads
7
+ @consumer_thread.join
8
+ @remote_io_thread.join
9
+ @local_io_thread.join
10
+ Process.wait @notify_daemon_pid
11
+ end
12
+
13
+ def kill_off_threads
14
+ Process.kill("TERM", @notify_daemon_pid) rescue nil
15
+ @consumer_thread.terminate
16
+ @remote_io_thread.terminate
17
+ @local_io_thread.terminate
18
+ end
19
+
20
+ def start_notify_daemon
21
+ logger.info('starting notify daemon')
22
+ r,w = IO.pipe
23
+ @notify_daemon_pid = spawn(start_notify_daemon_cmd, out: w)
24
+ w.close
25
+ @notify_reader = r
26
+ end
27
+
28
+ def start_remote_io
29
+ logger.info('starting remote IO')
30
+ @remote_io_thread = Thread.new do
31
+ begin
32
+ loop do
33
+ msg = Marshal.load(@remote_reader)
34
+ next if msg.nil?
35
+
36
+ case msg[:type]
37
+ when :new_changes
38
+ process_new_changes(msg[:content])
39
+ when :entangled_files
40
+ process_entangled_files(msg[:content])
41
+ end
42
+ end
43
+ rescue => e
44
+ $stderr.puts e.message
45
+ $stderr.puts e.backtrace.join("\n")
46
+ kill_off_threads
47
+ end
48
+ end
49
+ end
50
+
51
+ def start_local_io
52
+ logger.info('starting local IO')
53
+ @local_action_queue = Queue.new
54
+ @local_io_thread = Thread.new do
55
+ begin
56
+ msg = []
57
+ loop do
58
+ ready = IO.select([@notify_reader]).first
59
+ next unless ready && ready.any?
60
+ break if ready.first.eof?
61
+ line = ready.first.gets
62
+ next if line.nil? || line.empty?
63
+ line = line.strip
64
+ next if line == '-'
65
+ @local_action_queue.push line
66
+ end
67
+ rescue => e
68
+ $stderr.puts e.message
69
+ $stderr.puts e.backtrace.join("\n")
70
+ kill_off_threads
71
+ end
72
+ end
73
+ end
74
+
75
+ def start_local_consumer
76
+ @consumer_thread = Thread.new do
77
+ loop do
78
+ msg = [@local_action_queue.pop]
79
+ loop do
80
+ sleep 0.2
81
+ break if @local_action_queue.empty?
82
+ while !@local_action_queue.empty?
83
+ msg << @local_action_queue.pop
84
+ end
85
+ end
86
+ while Time.now.to_f <= @notify_sleep
87
+ sleep 0.5
88
+ while !@local_action_queue.empty?
89
+ msg << @local_action_queue.pop
90
+ end
91
+ end
92
+ process_lines(msg.uniq)
93
+ msg = []
94
+ sleep 0.5
95
+ end
96
+ end
97
+ end
98
+
99
+ def start_notify_daemon_cmd
100
+ uname = `uname`.strip.downcase
101
+ raise 'Unsupported OS' unless ['darwin', 'linux'].include?(uname)
102
+
103
+ "#{File.join(File.dirname(File.dirname(File.dirname(File.dirname(__FILE__)))), 'notifier', 'bin', uname, 'notify')} #{self.base_dir}"
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,24 @@
1
+ module Entangler
2
+ module Executor
3
+ module Background
4
+ module Master
5
+ protected
6
+ def start_remote_slave
7
+ require 'open3'
8
+ @remote_writer, @remote_reader, remote_err, @remote_thread = Open3.popen3("ssh -q #{@opts[:remote_user]}@#{@opts[:remote_host]} -p #{@opts[:remote_port]} -C \"source ~/.rvm/environments/default && entangler slave #{@opts[:remote_base_dir]}\"")
9
+ remote_err.close
10
+ end
11
+
12
+ def wait_for_threads
13
+ super
14
+ Process.wait @remote_thread[:pid] rescue nil
15
+ end
16
+
17
+ def kill_off_threads
18
+ Process.kill("INT", @remote_thread[:pid])
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,23 +1,32 @@
1
1
  require 'logger'
2
2
  require 'fileutils'
3
3
  require 'thread'
4
+ require_relative 'background/base'
5
+ require_relative 'processing/base'
4
6
 
5
7
  module Entangler
6
8
  module Executor
7
9
  class Base
10
+ include Entangler::Executor::Background::Base, Entangler::Executor::Processing::Base
11
+
8
12
  attr_reader :base_dir
9
13
 
10
14
  def initialize(base_dir, opts = {})
11
15
  @base_dir = File.realpath(File.expand_path(base_dir))
12
16
  @notify_sleep = 0
17
+ @exported_at = 0
13
18
  @opts = opts
14
19
  @opts[:ignore] = [/^\/\.git.*/, /^\/\.entangler.*/, /^\/\.idea.*/, /^\/log.*/, /^\/tmp.*/] unless @opts.has_key?(:ignore)
15
20
  validate_opts
16
21
  logger.info("Starting executor")
17
22
  end
18
23
 
19
- def validate_opts
20
- raise "Base directory doesn't exist" unless Dir.exists?(self.base_dir)
24
+ def generate_abs_path(rel_path)
25
+ File.join(self.base_dir, rel_path)
26
+ end
27
+
28
+ def strip_base_path(path, base_dir = self.base_dir)
29
+ File.expand_path(path).sub(base_dir, '')
21
30
  end
22
31
 
23
32
  def run
@@ -27,214 +36,18 @@ module Entangler
27
36
  start_local_consumer
28
37
  logger.debug("NOTIFY PID: #{@notify_daemon_pid}")
29
38
  Signal.trap("INT") { kill_off_threads }
30
- @consumer_thread.join
31
- @remote_io_thread.join
32
- @local_io_thread.join
33
- Process.wait @notify_daemon_pid
34
- end
35
-
36
- def kill_off_threads
37
- Process.kill("TERM", @notify_daemon_pid) rescue nil
38
- @consumer_thread.terminate
39
- @remote_io_thread.terminate
40
- @local_io_thread.terminate
41
- end
42
-
43
- def start_file_transfers(paths, pipe)
44
- Marshal.dump(paths.map{|path| EntangledFile.new(path) }, pipe)
39
+ wait_for_threads
45
40
  end
46
41
 
47
- def start_notify_daemon
48
- logger.info('starting notify daemon')
49
- r,w = IO.pipe
50
- @notify_daemon_pid = spawn(start_notify_daemon_cmd, out: w)
51
- w.close
52
- @notify_reader = r
53
- end
54
-
55
- def start_local_io
56
- logger.info('starting local IO')
57
- @local_action_queue = Queue.new
58
- @local_io_thread = Thread.new do
59
- begin
60
- msg = []
61
- loop do
62
- ready = IO.select([@notify_reader]).first
63
- next unless ready && ready.any?
64
- break if ready.first.eof?
65
- line = ready.first.gets
66
- next if line.nil? || line.empty?
67
- line = line.strip
68
- next if line == '-'
69
- @local_action_queue.push line
70
- end
71
- rescue => e
72
- $stderr.puts e.message
73
- $stderr.puts e.backtrace.join("\n")
74
- kill_off_threads
75
- end
76
- end
77
- end
78
-
79
- def start_local_consumer
80
- @consumer_thread = Thread.new do
81
- loop do
82
- msg = [@local_action_queue.pop]
83
- while !@local_action_queue.empty?
84
- msg << @local_action_queue.pop
85
- end
86
- while Time.now.to_i <= @notify_sleep
87
- sleep 1
88
- while !@local_action_queue.empty?
89
- msg << @local_action_queue.pop
90
- end
91
- end
92
- process_lines(msg.uniq)
93
- msg = []
94
- sleep 1
95
- end
96
- end
42
+ protected
43
+ def validate_opts
44
+ raise "Base directory doesn't exist" unless Dir.exists?(self.base_dir)
97
45
  end
98
46
 
99
47
  def send_to_remote(msg = {})
100
48
  Marshal.dump(msg, @remote_writer)
101
49
  end
102
50
 
103
- def start_remote_io
104
- logger.info('starting remote IO')
105
- @remote_io_thread = Thread.new do
106
- begin
107
- loop do
108
- msg = Marshal.load(@remote_reader)
109
- next if msg.nil?
110
-
111
- case msg[:type]
112
- when :new_changes
113
- logger.debug("Got #{msg[:content].length} new folder changes from remote")
114
-
115
- created_dirs = []
116
- dirs_to_remove = []
117
- files_to_remove = []
118
- files_to_update = []
119
-
120
- msg[:content].each do |base, changes|
121
- possible_creation_dirs = changes[:dirs].clone
122
- possible_creation_files = changes[:files].keys.clone
123
- full_base_path = generate_abs_path(base)
124
-
125
- unless File.directory?(full_base_path)
126
- FileUtils::mkdir_p(full_base_path)
127
- @notify_sleep = Time.now.to_i + 60
128
- end
129
-
130
- Dir.entries(full_base_path).each do |f|
131
- next if ['.', '..'].include? f
132
- full_path = File.join(generate_abs_path(base), f)
133
- if File.directory?(full_path)
134
- possible_creation_dirs -= [f]
135
- dirs_to_remove << full_path unless changes[:dirs].include?(f)
136
- elsif changes[:files].has_key?(f)
137
- possible_creation_files -= [f]
138
- files_to_update << File.join(base, f) unless changes[:files][f] == [File.size(full_path), File.mtime(full_path).to_i]
139
- else
140
- files_to_remove << full_path
141
- end
142
- end
143
-
144
- dirs_to_create = possible_creation_dirs.map{|d| File.join(generate_abs_path(base), d)}
145
- if dirs_to_create.any?
146
- logger.debug("Creating #{dirs_to_create.length} dirs")
147
- @notify_sleep = Time.now.to_i + 60
148
- FileUtils.mkdir_p dirs_to_create
149
- end
150
- created_dirs += dirs_to_create
151
- files_to_update += possible_creation_files.map{|f| File.join(base, f)}
152
- end
153
-
154
- @notify_sleep = Time.now.to_i + 60 if (files_to_remove + created_dirs + dirs_to_remove + files_to_update).any?
155
-
156
- if files_to_remove.any?
157
- logger.debug("Deleting #{files_to_remove.length} files")
158
- FileUtils.rm files_to_remove
159
- end
160
- if dirs_to_remove.any?
161
- logger.debug("Deleting #{dirs_to_remove.length} dirs")
162
- FileUtils.rm_r dirs_to_remove
163
- end
164
- if files_to_update.any?
165
- logger.debug("Creating #{files_to_update.length} new entangled files to sync")
166
- send_to_remote(type: :entangled_files, content: files_to_update.map{|f| Entangler::EntangledFile.new(f) })
167
- end
168
- @notify_sleep = Time.now.to_i + 1 if (files_to_remove + created_dirs + dirs_to_remove + files_to_update).any?
169
- @notify_sleep += 60 if files_to_update.any?
170
- when :entangled_files
171
- logger.debug("Got #{msg[:content].length} entangled files from remote")
172
- completed_files, updated_files = msg[:content].partition(&:done?)
173
-
174
- completed_files.each(&:export)
175
-
176
- updated_files = updated_files.find_all{|f| f.state != 1 || f.file_exists? }
177
- if updated_files.any?
178
- send_to_remote(type: :entangled_files, content: updated_files)
179
- end
180
- @notify_sleep = Time.now.to_i + 1 if completed_files.any?
181
- end
182
- end
183
- rescue => e
184
- $stderr.puts e.message
185
- $stderr.puts e.backtrace.join("\n")
186
- kill_off_threads
187
- end
188
- end
189
- end
190
-
191
- def process_lines(lines)
192
- to_process = lines.map do |line|
193
- path = line[2..-1]
194
- stripped_path = strip_base_path(path)
195
- next unless @opts[:ignore].nil? || @opts[:ignore].none?{|i| stripped_path.match(i) }
196
- next unless File.directory?(path)
197
-
198
- [stripped_path, generate_file_list(path)]
199
- end.compact.sort_by(&:first)
200
-
201
- return unless to_process.any?
202
- logger.debug("PROCESSING #{to_process.count} folder/s")
203
- send_to_remote(type: :new_changes, content: to_process)
204
- end
205
-
206
- def generate_file_list(path)
207
- dirs = []
208
- files = {}
209
-
210
- Dir.entries(path).each do |f|
211
- next if ['.', '..'].include? f
212
- f_path = File.join(path, f)
213
- if File.directory? f_path
214
- dirs << f
215
- else
216
- files[f] = [File.size(f_path), File.mtime(f_path).to_i]
217
- end
218
- end
219
-
220
- {dirs: dirs, files: files}
221
- end
222
-
223
- def generate_abs_path(rel_path)
224
- File.join(self.base_dir, rel_path)
225
- end
226
-
227
- def strip_base_path(path, base_dir = self.base_dir)
228
- File.expand_path(path).sub(base_dir, '')
229
- end
230
-
231
- def start_notify_daemon_cmd
232
- uname = `uname`.strip.downcase
233
- raise 'Unsupported OS' unless ['darwin', 'linux'].include?(uname)
234
-
235
- "#{File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'notifier', 'bin', uname, 'notify')} #{self.base_dir}"
236
- end
237
-
238
51
  def logger
239
52
  FileUtils::mkdir_p log_dir
240
53
  @logger ||= Logger.new(File.join(log_dir, 'entangler.log'))
@@ -1,30 +1,29 @@
1
+ require_relative 'background/master'
2
+
1
3
  module Entangler
2
4
  module Executor
3
5
  class Master < Base
4
- def validate_opts
5
- super
6
- raise 'Missing remote base dir' unless @opts.keys.include?(:remote_base_dir)
7
- raise 'Missing remote user' unless @opts.keys.include?(:remote_user)
8
- raise 'Missing remote host' unless @opts.keys.include?(:remote_host)
9
- @opts[:remote_port] ||= '22'
10
- res = `ssh -q #{@opts[:remote_user]}@#{@opts[:remote_host]} -p #{@opts[:remote_port]} -C "[[ -d '#{@opts[:remote_base_dir]}' ]] && echo 'ok' || echo 'missing'"`
11
- raise 'Cannot connect to remote' if res.empty?
12
- raise 'Remote base dir invalid' unless res.strip == 'ok'
13
- end
6
+ include Entangler::Executor::Background::Master
14
7
 
15
8
  def run
16
9
  perform_initial_rsync
17
10
  sleep 1
18
11
  start_remote_slave
19
12
  super
20
- Process.wait @remote_thread[:pid] rescue nil
21
13
  @remote_writer.close
22
14
  @remote_reader.close
23
15
  end
24
16
 
25
- def kill_off_threads
26
- Process.kill("INT", @remote_thread[:pid])
17
+ private
18
+ def validate_opts
27
19
  super
20
+ raise 'Missing remote base dir' unless @opts.keys.include?(:remote_base_dir)
21
+ raise 'Missing remote user' unless @opts.keys.include?(:remote_user)
22
+ raise 'Missing remote host' unless @opts.keys.include?(:remote_host)
23
+ @opts[:remote_port] ||= '22'
24
+ res = `ssh -q #{@opts[:remote_user]}@#{@opts[:remote_host]} -p #{@opts[:remote_port]} -C "[[ -d '#{@opts[:remote_base_dir]}' ]] && echo 'ok' || echo 'missing'"`
25
+ raise 'Cannot connect to remote' if res.empty?
26
+ raise 'Remote base dir invalid' unless res.strip == 'ok'
28
27
  end
29
28
 
30
29
  def perform_initial_rsync
@@ -34,12 +33,6 @@ module Entangler
34
33
  end
35
34
  logger.debug 'Initial sync complete'
36
35
  end
37
-
38
- def start_remote_slave
39
- require 'open3'
40
- @remote_writer, @remote_reader, remote_err, @remote_thread = Open3.popen3("ssh -q #{@opts[:remote_user]}@#{@opts[:remote_host]} -p #{@opts[:remote_port]} -C \"source ~/.rvm/environments/default && entangler slave #{@opts[:remote_base_dir]}\"")
41
- remote_err.close
42
- end
43
36
  end
44
37
  end
45
38
  end
@@ -0,0 +1,122 @@
1
+ module Entangler
2
+ module Executor
3
+ module Processing
4
+ module Base
5
+ protected
6
+ def generate_file_list(path)
7
+ dirs = []
8
+ files = {}
9
+
10
+ Dir.entries(path).each do |f|
11
+ next if ['.', '..'].include? f
12
+ f_path = File.join(path, f)
13
+ if File.directory? f_path
14
+ dirs << f
15
+ else
16
+ files[f] = [File.size(f_path), File.mtime(f_path).to_i]
17
+ end
18
+ end
19
+
20
+ {dirs: dirs, files: files}
21
+ end
22
+
23
+ def process_new_changes(content)
24
+ logger.debug("Got #{content.length} new folder changes from remote")
25
+
26
+ created_dirs = []
27
+ dirs_to_remove = []
28
+ files_to_remove = []
29
+ files_to_update = []
30
+
31
+ content.each do |base, changes|
32
+ possible_creation_dirs = changes[:dirs].clone
33
+ possible_creation_files = changes[:files].keys.clone
34
+ full_base_path = generate_abs_path(base)
35
+
36
+ unless File.directory?(full_base_path)
37
+ FileUtils::mkdir_p(full_base_path)
38
+ @notify_sleep = Time.now.to_i + 60
39
+ end
40
+
41
+ Dir.entries(full_base_path).each do |f|
42
+ next if ['.', '..'].include? f
43
+ full_path = File.join(generate_abs_path(base), f)
44
+ if File.directory?(full_path)
45
+ possible_creation_dirs -= [f]
46
+ dirs_to_remove << full_path unless changes[:dirs].include?(f)
47
+ elsif changes[:files].has_key?(f)
48
+ possible_creation_files -= [f]
49
+ files_to_update << File.join(base, f) unless changes[:files][f] == [File.size(full_path), File.mtime(full_path).to_i]
50
+ else
51
+ files_to_remove << full_path
52
+ end
53
+ end
54
+
55
+ dirs_to_create = possible_creation_dirs.map{|d| File.join(generate_abs_path(base), d)}
56
+ if dirs_to_create.any?
57
+ logger.debug("Creating #{dirs_to_create.length} dirs")
58
+ @notify_sleep = Time.now.to_i + 60
59
+ FileUtils.mkdir_p dirs_to_create
60
+ end
61
+ created_dirs += dirs_to_create
62
+ files_to_update += possible_creation_files.map{|f| File.join(base, f)}
63
+ end
64
+
65
+ @notify_sleep = Time.now.to_i + 60 if (files_to_remove + created_dirs + dirs_to_remove + files_to_update).any?
66
+
67
+ if files_to_remove.any?
68
+ logger.debug("Deleting #{files_to_remove.length} files")
69
+ FileUtils.rm files_to_remove
70
+ end
71
+ if dirs_to_remove.any?
72
+ logger.debug("Deleting #{dirs_to_remove.length} dirs")
73
+ FileUtils.rm_r dirs_to_remove
74
+ end
75
+ if files_to_update.any?
76
+ logger.debug("Creating #{files_to_update.length} new entangled files to sync")
77
+ send_to_remote(type: :entangled_files, content: files_to_update.map{|f| Entangler::EntangledFile.new(f) })
78
+ end
79
+ @notify_sleep = Time.now.to_f + 0.5 if (files_to_remove + created_dirs + dirs_to_remove + files_to_update).any?
80
+ @notify_sleep += 60 if files_to_update.any?
81
+ end
82
+
83
+ def process_entangled_files(content)
84
+ logger.debug("Got #{content.length} entangled files from remote")
85
+ completed_files, updated_files = content.partition(&:done?)
86
+
87
+ if completed_files.any?
88
+ @exported_at = Time.now.to_f
89
+ @exported_folders = completed_files.map{|ef| "#{File.dirname(generate_abs_path(ef.path))}/" }.uniq
90
+ completed_files.each(&:export)
91
+ end
92
+
93
+ updated_files = updated_files.find_all{|f| f.state != 1 || f.file_exists? }
94
+ if updated_files.any?
95
+ send_to_remote(type: :entangled_files, content: updated_files)
96
+ end
97
+ @notify_sleep = Time.now.to_f + 0.5 if completed_files.any?
98
+ end
99
+
100
+ def process_lines(lines)
101
+ paths = lines.map{|line| line[2..-1] }
102
+
103
+ if @exported_at < Time.now.to_f && Time.now.to_f < @exported_at + 2
104
+ paths -= @exported_folders
105
+ end
106
+
107
+ to_process = paths.map do |path|
108
+ stripped_path = strip_base_path(path)
109
+ next unless @opts[:ignore].nil? || @opts[:ignore].none?{|i| stripped_path.match(i) }
110
+ next unless File.directory?(path)
111
+
112
+ [stripped_path, generate_file_list(path)]
113
+ end.compact.sort_by(&:first)
114
+
115
+ return unless to_process.any?
116
+ logger.debug("PROCESSING #{to_process.count} folder/s")
117
+ send_to_remote(type: :new_changes, content: to_process)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -1,3 +1,3 @@
1
1
  module Entangler
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/entangler.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'entangler/version'
2
- require 'entangler/entangled_file'
1
+ require_relative 'entangler/version'
2
+ require_relative 'entangler/entangled_file'
3
3
 
4
4
  module Entangler
5
5
  class << self
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entangler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Allie
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-10-24 00:00:00.000000000 Z
11
+ date: 2016-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -88,8 +88,11 @@ files:
88
88
  - exe/entangler
89
89
  - lib/entangler.rb
90
90
  - lib/entangler/entangled_file.rb
91
+ - lib/entangler/executor/background/base.rb
92
+ - lib/entangler/executor/background/master.rb
91
93
  - lib/entangler/executor/base.rb
92
94
  - lib/entangler/executor/master.rb
95
+ - lib/entangler/executor/processing/base.rb
93
96
  - lib/entangler/executor/slave.rb
94
97
  - lib/entangler/version.rb
95
98
  - lib/notifier/bin/darwin/notify