entangler 0.4.1 → 1.0.0.beta1
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 +4 -4
- data/.rubocop.yml +9 -0
- data/.travis.yml +17 -2
- data/README.md +12 -12
- data/Rakefile +5 -3
- data/bin/console +3 -3
- data/entangler.gemspec +15 -14
- data/exe/entangler +30 -19
- data/lib/entangler/entangled_file.rb +31 -102
- data/lib/entangler/executor/background/base.rb +79 -74
- data/lib/entangler/executor/background/master.rb +8 -3
- data/lib/entangler/executor/base.rb +19 -16
- data/lib/entangler/executor/master.rb +74 -24
- data/lib/entangler/executor/slave.rb +1 -1
- data/lib/entangler/version.rb +1 -1
- data/lib/entangler.rb +2 -2
- metadata +25 -25
- data/lib/entangler/executor/processing/base.rb +0 -122
- data/lib/notifier/README.md +0 -3
- data/lib/notifier/bin/darwin/notify +0 -0
- data/lib/notifier/bin/linux/notify +0 -0
- data/lib/notifier/src/darwin/BUILD +0 -7
- data/lib/notifier/src/darwin/README +0 -12
- data/lib/notifier/src/darwin/notify.c +0 -63
- data/lib/notifier/src/linux/BUILD +0 -4
- data/lib/notifier/src/linux/README +0 -18
- data/lib/notifier/src/linux/notify.c +0 -296
- data/lib/notifier/src/linux/old/BUILD +0 -11
- data/lib/notifier/src/linux/old/README +0 -14
- data/lib/notifier/src/linux/old/kernel-filesystem-monitor-daemon-cat.cpp +0 -165
- data/lib/notifier/src/linux/old/kernel-filesystem-monitor-daemon.cpp +0 -727
- data/lib/notifier/src/linux/old/kernel-filesystem-monitor-daemon.hh +0 -212
@@ -3,9 +3,10 @@ module Entangler
|
|
3
3
|
module Background
|
4
4
|
module Master
|
5
5
|
protected
|
6
|
+
|
6
7
|
def start_remote_slave
|
7
8
|
require 'open3'
|
8
|
-
ignore_opts = @opts[:ignore].map{|regexp| "-i '#{regexp.inspect}'"}.join(' ')
|
9
|
+
ignore_opts = @opts[:ignore].map { |regexp| "-i '#{regexp.inspect}'" }.join(' ')
|
9
10
|
entangler_cmd = "entangler slave #{@opts[:remote_base_dir]} #{ignore_opts}"
|
10
11
|
ssh_cmd = generate_ssh_command("source ~/.rvm/environments/default && #{entangler_cmd}")
|
11
12
|
full_cmd = @opts[:remote_mode] ? ssh_cmd : entangler_cmd
|
@@ -16,11 +17,15 @@ module Entangler
|
|
16
17
|
|
17
18
|
def wait_for_threads
|
18
19
|
super
|
19
|
-
|
20
|
+
begin
|
21
|
+
Process.wait @remote_thread[:pid]
|
22
|
+
rescue
|
23
|
+
nil
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
def kill_off_threads
|
23
|
-
Process.kill(
|
28
|
+
Process.kill('INT', @remote_thread[:pid])
|
24
29
|
super
|
25
30
|
end
|
26
31
|
end
|
@@ -2,29 +2,28 @@ require 'logger'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'thread'
|
4
4
|
require_relative 'background/base'
|
5
|
-
require_relative 'processing/base'
|
6
5
|
|
7
6
|
module Entangler
|
8
7
|
module Executor
|
9
8
|
class Base
|
10
|
-
include Entangler::Executor::Background::Base
|
9
|
+
include Entangler::Executor::Background::Base
|
11
10
|
|
12
11
|
attr_reader :base_dir
|
13
12
|
|
14
13
|
def initialize(base_dir, opts = {})
|
15
14
|
@base_dir = File.realpath(File.expand_path(base_dir))
|
16
|
-
@
|
17
|
-
@
|
15
|
+
@recently_received_paths = []
|
16
|
+
@listener_pauses = [false, false]
|
18
17
|
@opts = opts
|
19
|
-
@opts[:ignore] = [
|
20
|
-
@opts[:ignore] <<
|
18
|
+
@opts[:ignore] = [/^\.git.*/] unless @opts.key?(:ignore)
|
19
|
+
@opts[:ignore] << /^\.entangler.*/
|
21
20
|
|
22
21
|
validate_opts
|
23
|
-
logger.info(
|
22
|
+
logger.info('Starting executor')
|
24
23
|
end
|
25
24
|
|
26
25
|
def generate_abs_path(rel_path)
|
27
|
-
File.join(
|
26
|
+
File.join(base_dir, rel_path)
|
28
27
|
end
|
29
28
|
|
30
29
|
def strip_base_path(path, base_dir = self.base_dir)
|
@@ -32,18 +31,18 @@ module Entangler
|
|
32
31
|
end
|
33
32
|
|
34
33
|
def run
|
35
|
-
|
36
|
-
start_local_io
|
34
|
+
start_listener
|
37
35
|
start_remote_io
|
38
|
-
|
39
|
-
logger.debug("NOTIFY PID: #{@notify_daemon_pid}")
|
40
|
-
Signal.trap("INT") { kill_off_threads }
|
36
|
+
Signal.trap('INT') { kill_off_threads }
|
41
37
|
wait_for_threads
|
38
|
+
ensure
|
39
|
+
stop_listener
|
42
40
|
end
|
43
41
|
|
44
42
|
protected
|
43
|
+
|
45
44
|
def validate_opts
|
46
|
-
raise "Base directory doesn't exist" unless Dir.
|
45
|
+
raise "Base directory doesn't exist" unless Dir.exist?(base_dir)
|
47
46
|
end
|
48
47
|
|
49
48
|
def send_to_remote(msg = {})
|
@@ -51,8 +50,12 @@ module Entangler
|
|
51
50
|
end
|
52
51
|
|
53
52
|
def logger
|
54
|
-
FileUtils
|
55
|
-
@logger ||=
|
53
|
+
FileUtils.mkdir_p log_dir
|
54
|
+
@logger ||= begin
|
55
|
+
l = Logger.new(File.join(log_dir, 'entangler.log'))
|
56
|
+
l.level = @opts[:verbose] ? Logger::DEBUG : Logger::INFO
|
57
|
+
l
|
58
|
+
end
|
56
59
|
end
|
57
60
|
|
58
61
|
def log_dir
|
@@ -15,49 +15,99 @@ module Entangler
|
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
|
+
|
18
19
|
def validate_opts
|
19
20
|
super
|
20
21
|
if @opts[:remote_mode]
|
21
|
-
raise 'Missing remote base dir' unless @opts.keys.include?(:remote_base_dir)
|
22
|
-
raise 'Missing remote user' unless @opts.keys.include?(:remote_user)
|
23
|
-
raise 'Missing remote host' unless @opts.keys.include?(:remote_host)
|
24
22
|
@opts[:remote_port] ||= '22'
|
25
|
-
|
26
|
-
raise 'Cannot connect to remote' if res.empty?
|
27
|
-
raise 'Remote base dir invalid' unless res.strip == 'ok'
|
23
|
+
validate_remote_opts
|
28
24
|
else
|
29
|
-
|
30
|
-
raise "Destination directory can't be the same as the base directory" if @opts[:remote_base_dir] == self.base_dir
|
31
|
-
raise "Destination directory doesn't exist" unless Dir.exists?(@opts[:remote_base_dir])
|
25
|
+
validate_local_opts
|
32
26
|
end
|
33
27
|
end
|
34
28
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
29
|
+
def validate_local_opts
|
30
|
+
@opts[:remote_base_dir] = File.realpath(File.expand_path(@opts[:remote_base_dir]))
|
31
|
+
raise "Destination directory can't be the same as the base directory" if @opts[:remote_base_dir] == base_dir
|
32
|
+
raise "Destination directory doesn't exist" unless Dir.exist?(@opts[:remote_base_dir])
|
33
|
+
end
|
38
34
|
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
def validate_remote_opts
|
36
|
+
keys = @opts.keys
|
37
|
+
raise 'Missing remote base dir' unless keys.include?(:remote_base_dir)
|
38
|
+
raise 'Missing remote user' unless keys.include?(:remote_user)
|
39
|
+
raise 'Missing remote host' unless keys.include?(:remote_host)
|
40
|
+
validate_remote_base_dir
|
41
|
+
validate_remote_entangler_version
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
def validate_remote_base_dir
|
45
|
+
res = `#{generate_ssh_command("[[ -d '#{@opts[:remote_base_dir]}' ]] && echo 'ok' || echo 'missing'")}`
|
46
|
+
raise 'Cannot connect to remote' if res.empty?
|
47
|
+
raise 'Remote base dir invalid' unless res.strip == 'ok'
|
48
|
+
end
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
+
def validate_remote_entangler_version
|
51
|
+
return unless @opts[:remote_mode]
|
52
|
+
res = `#{generate_ssh_command('source ~/.rvm/environments/default && entangler --version')}`
|
53
|
+
remote_version = Gem::Version.new(res.strip)
|
54
|
+
local_version = Gem::Version.new(Entangler::VERSION)
|
55
|
+
return unless major_version_mismatch?(local_version, remote_version)
|
56
|
+
raise 'Entangler version too far apart, please update either local or remote Entangler.' \
|
57
|
+
" Local version is #{local_version} and remote version is #{remote_version}."
|
58
|
+
end
|
50
59
|
|
51
|
-
|
60
|
+
def major_version_mismatch?(version1, version2)
|
61
|
+
version1.segments[0] != version2.segments[0] ||
|
62
|
+
(version1.segments[0].zero? && version1 != version2) ||
|
63
|
+
((version1.prerelease? || version2.prerelease?) && version1 != version2)
|
64
|
+
end
|
52
65
|
|
53
|
-
|
66
|
+
def perform_initial_rsync
|
67
|
+
logger.info 'Running initial sync'
|
68
|
+
IO.popen(rsync_cmd_string).each do |line|
|
54
69
|
logger.debug line.chomp
|
55
70
|
end
|
56
71
|
logger.debug 'Initial sync complete'
|
57
72
|
end
|
58
73
|
|
74
|
+
def find_all_folders
|
75
|
+
local_folders = process_raw_file_list(`find #{base_dir} -type d`, base_dir)
|
76
|
+
|
77
|
+
remote_find_cmd = "find #{@opts[:remote_base_dir]} -type d"
|
78
|
+
raw_remote_folders = `#{@opts[:remote_mode] ? generate_ssh_command(remote_find_cmd) : remote_find_cmd}`
|
79
|
+
remote_folders = process_raw_file_list(raw_remote_folders, @opts[:remote_base_dir])
|
80
|
+
|
81
|
+
remote_folders | local_folders
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_raw_file_list(output, base)
|
85
|
+
output.split("\n").tap { |a| a.shift(1) }
|
86
|
+
.map { |path| path.sub("#{base}/", '') }
|
87
|
+
end
|
88
|
+
|
89
|
+
def find_rsync_ignore_folders
|
90
|
+
find_all_folders.map do |path|
|
91
|
+
@opts[:ignore].map { |regexp| (regexp.match(path) || [])[0] }.compact.first
|
92
|
+
end.compact.uniq
|
93
|
+
end
|
94
|
+
|
59
95
|
def generate_ssh_command(cmd)
|
60
|
-
"ssh -q #{
|
96
|
+
"ssh -q #{remote_hostname} -p #{@opts[:remote_port]} -C \"#{cmd}\""
|
97
|
+
end
|
98
|
+
|
99
|
+
def remote_hostname
|
100
|
+
"#{@opts[:remote_user]}@#{@opts[:remote_host]}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def rsync_cmd_string
|
104
|
+
exclude_args = find_rsync_ignore_folders.map { |path| "--exclude #{path}" }.join(' ')
|
105
|
+
remote_path = @opts[:remote_mode] ? "#{@opts[:remote_user]}@#{@opts[:remote_host]}:" : ''
|
106
|
+
remote_path += "#{@opts[:remote_base_dir]}/"
|
107
|
+
|
108
|
+
cmd = "rsync -azv #{exclude_args}"
|
109
|
+
cmd += " -e \"ssh -p #{@opts[:remote_port]}\"" if @opts[:remote_mode]
|
110
|
+
cmd + " --delete #{base_dir}/ #{remote_path}"
|
61
111
|
end
|
62
112
|
end
|
63
113
|
end
|
data/lib/entangler/version.rb
CHANGED
data/lib/entangler.rb
CHANGED
@@ -6,7 +6,7 @@ module Entangler
|
|
6
6
|
attr_accessor :executor
|
7
7
|
|
8
8
|
def run(base_dir, opts = {})
|
9
|
-
opts = {mode: 'master', remote_mode: true}.merge(opts)
|
9
|
+
opts = { mode: 'master', remote_mode: true }.merge(opts)
|
10
10
|
|
11
11
|
require 'entangler/executor/base'
|
12
12
|
if opts[:mode] == 'master'
|
@@ -17,7 +17,7 @@ module Entangler
|
|
17
17
|
self.executor = Entangler::Executor::Slave.new(base_dir, opts)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
executor.run
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
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.
|
4
|
+
version: 1.0.0.beta1
|
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-12-
|
11
|
+
date: 2016-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -53,19 +53,33 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
61
|
+
version: '0.46'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.46'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: listen
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.1'
|
62
76
|
type: :runtime
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
82
|
+
version: '3.1'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: to_regexp
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,7 +94,7 @@ dependencies:
|
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0.2'
|
83
|
-
description: Two way file syncer using platform native notify
|
97
|
+
description: Two way file syncer using platform native notify.
|
84
98
|
email:
|
85
99
|
- dave@daveallie.com
|
86
100
|
executables:
|
@@ -90,6 +104,7 @@ extra_rdoc_files: []
|
|
90
104
|
files:
|
91
105
|
- ".gitignore"
|
92
106
|
- ".rspec"
|
107
|
+
- ".rubocop.yml"
|
93
108
|
- ".travis.yml"
|
94
109
|
- CODE_OF_CONDUCT.md
|
95
110
|
- Gemfile
|
@@ -106,23 +121,8 @@ files:
|
|
106
121
|
- lib/entangler/executor/background/master.rb
|
107
122
|
- lib/entangler/executor/base.rb
|
108
123
|
- lib/entangler/executor/master.rb
|
109
|
-
- lib/entangler/executor/processing/base.rb
|
110
124
|
- lib/entangler/executor/slave.rb
|
111
125
|
- lib/entangler/version.rb
|
112
|
-
- lib/notifier/README.md
|
113
|
-
- lib/notifier/bin/darwin/notify
|
114
|
-
- lib/notifier/bin/linux/notify
|
115
|
-
- lib/notifier/src/darwin/BUILD
|
116
|
-
- lib/notifier/src/darwin/README
|
117
|
-
- lib/notifier/src/darwin/notify.c
|
118
|
-
- lib/notifier/src/linux/BUILD
|
119
|
-
- lib/notifier/src/linux/README
|
120
|
-
- lib/notifier/src/linux/notify.c
|
121
|
-
- lib/notifier/src/linux/old/BUILD
|
122
|
-
- lib/notifier/src/linux/old/README
|
123
|
-
- lib/notifier/src/linux/old/kernel-filesystem-monitor-daemon-cat.cpp
|
124
|
-
- lib/notifier/src/linux/old/kernel-filesystem-monitor-daemon.cpp
|
125
|
-
- lib/notifier/src/linux/old/kernel-filesystem-monitor-daemon.hh
|
126
126
|
homepage: https://github.com/daveallie/entangler
|
127
127
|
licenses:
|
128
128
|
- MIT
|
@@ -138,13 +138,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
138
|
version: '0'
|
139
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
140
|
requirements:
|
141
|
-
- - "
|
141
|
+
- - ">"
|
142
142
|
- !ruby/object:Gem::Version
|
143
|
-
version:
|
143
|
+
version: 1.3.1
|
144
144
|
requirements: []
|
145
145
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.
|
146
|
+
rubygems_version: 2.4.8
|
147
147
|
signing_key:
|
148
148
|
specification_version: 4
|
149
|
-
summary: Two way file syncer using platform native notify
|
149
|
+
summary: Two way file syncer using platform native notify.
|
150
150
|
test_files: []
|
@@ -1,122 +0,0 @@
|
|
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("RECIEVING #{content.length} folder/s from remote:\n#{content.map{|c| "#{c[0][1..-1]}/"}.join("\n")}")
|
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 file/s")
|
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("UPDATING #{content.length} entangled file/s 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:\n#{to_process.map{|c| "#{c[0][1..-1]}/"}.join("\n")}")
|
117
|
-
send_to_remote(type: :new_changes, content: to_process)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
data/lib/notifier/README.md
DELETED
@@ -1,3 +0,0 @@
|
|
1
|
-
The code in the following subdirectories comes from https://github.com/DmitryKoterov/dklab_realsync, unmodified.
|
2
|
-
|
3
|
-
It is being redistrubuted under GPL, which it was originally provided under. For more information on GPL, please see https://www.gnu.org/licenses/gpl-3.0.en.html.
|
Binary file
|
Binary file
|
@@ -1,12 +0,0 @@
|
|
1
|
-
The notify utility continiously prints changes in a specified directory in the following format:
|
2
|
-
|
3
|
-
M changed/path/1
|
4
|
-
M changed/path/2
|
5
|
-
-
|
6
|
-
|
7
|
-
|
8
|
-
Where M stands for "Modifed", and "-" is the indicator of end of changeset
|
9
|
-
|
10
|
-
Utility only returns specific directories that have changed, it does not print
|
11
|
-
the files/directories that have been modified: you need to determine them
|
12
|
-
yourself
|
@@ -1,63 +0,0 @@
|
|
1
|
-
#include <CoreServices/CoreServices.h>
|
2
|
-
#include <CoreFoundation/CoreFoundation.h>
|
3
|
-
#include <sys/stat.h>
|
4
|
-
|
5
|
-
static void printChangesFunc(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
|
6
|
-
char **paths = eventPaths;
|
7
|
-
int i;
|
8
|
-
for (i = 0; i < numEvents; i++) {
|
9
|
-
printf("M %s\n", paths[i]);
|
10
|
-
}
|
11
|
-
printf("-\n");
|
12
|
-
fflush(stdout);
|
13
|
-
}
|
14
|
-
|
15
|
-
void initFSEvents(const char *path) {
|
16
|
-
|
17
|
-
/* Define variables and create a CFArray object containing
|
18
|
-
CFString objects containing paths to watch.
|
19
|
-
*/
|
20
|
-
|
21
|
-
CFStringRef mypath = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
|
22
|
-
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
|
23
|
-
void *callbackInfo = NULL; // could put stream-specific data here.
|
24
|
-
FSEventStreamRef stream;
|
25
|
-
CFAbsoluteTime latency = 0.1; /* Latency in seconds */
|
26
|
-
|
27
|
-
/* Create the stream, passing in a callback */
|
28
|
-
stream = FSEventStreamCreate(NULL,
|
29
|
-
&printChangesFunc,
|
30
|
-
callbackInfo,
|
31
|
-
pathsToWatch,
|
32
|
-
kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
|
33
|
-
latency,
|
34
|
-
kFSEventStreamCreateFlagNone /* Flags explained in reference */
|
35
|
-
);
|
36
|
-
|
37
|
-
CFRelease(pathsToWatch);
|
38
|
-
CFRelease(mypath);
|
39
|
-
|
40
|
-
/* Create the stream before calling this. */
|
41
|
-
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
42
|
-
FSEventStreamStart(stream);
|
43
|
-
}
|
44
|
-
|
45
|
-
int main (int argc, const char * argv[]) {
|
46
|
-
|
47
|
-
if(argc != 2) {
|
48
|
-
printf("Usage: %s <path>\n", argv[0]);
|
49
|
-
return 1;
|
50
|
-
}
|
51
|
-
|
52
|
-
struct stat tmp;
|
53
|
-
|
54
|
-
if(stat(argv[1], &tmp) != 0) {
|
55
|
-
perror("Invalid path");
|
56
|
-
return 2;
|
57
|
-
}
|
58
|
-
|
59
|
-
initFSEvents(argv[1]);
|
60
|
-
CFRunLoopRun();
|
61
|
-
|
62
|
-
return 0;
|
63
|
-
}
|
@@ -1,18 +0,0 @@
|
|
1
|
-
The notify utility continiously prints changes in a specified directory in the following format:
|
2
|
-
|
3
|
-
M changed/path/1
|
4
|
-
M changed/path/2
|
5
|
-
-
|
6
|
-
|
7
|
-
Where M stands for "Modifed", and "-" is the indicator of end of changeset
|
8
|
-
|
9
|
-
Utility only returns specific directories that have changed, it does not print
|
10
|
-
the files/directories that have been modified: you need to determine them
|
11
|
-
yourself.
|
12
|
-
|
13
|
-
Linux-specific notes:
|
14
|
-
|
15
|
-
1. You might need to adjust '/proc/sys/fs/inotify/max_user_watches' to allow more directories to be watched
|
16
|
-
2. If you have a lot of changes you might also want to increase queue size in /proc/sys/fs/inotify/max_queued_events
|
17
|
-
3. Watched queue can overflow and notify utility can run out of watched directories.
|
18
|
-
When you get exit code 3, you need to restart the daemon and re-process all directories you are interested in.
|