docker-sync 0.0.15 → 0.1.0

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: f91f3a2eb84005eb9ecd865282ace48c86f2f2c4
4
- data.tar.gz: 3a5ca77ceab1cbe91ae630c6cd7c102db467f0c2
3
+ metadata.gz: 6cb5e3a077d9de57cad162afbdab55c0aa2ed36f
4
+ data.tar.gz: 73b3b75811e54265c180c4e6cc540a23f762a394
5
5
  SHA512:
6
- metadata.gz: 35de54d7b90e0dd76617a8ad102cea41ff8c837904790f96313c8943eb5b9c7e13249bfa3209673788fec538eb9784f173393dddfeff6f81e8a967be10feceda
7
- data.tar.gz: 30776d4c9c53279ffa349ac44f50efb9b204a7577678d67c44baaeef5131f94eab02e62d28ae423dbd641e3a62f7ae5fe7d0f9b8f86bf8a6bc38ba799adac901
6
+ metadata.gz: 420ff17cc42f4d5422e85604f5e28b1ff10e6a820435130bca44dccf6f970c349583d068195ca5f460a9c89b230ad94f255f56dac03f9b79b95036c54cb60eed
7
+ data.tar.gz: 0d1284902dcb5b72fe1cde3c28f9279efba62db2990f2c9c9837e3461b8f0032f2c61b6b2f1b588ba4fc6936cf220b195be25b3c3221d17d7e952674a77e6d61
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.15
1
+ 0.1.0
@@ -34,4 +34,23 @@ module Execution
34
34
 
35
35
  end
36
36
 
37
+ # unison doesn't work when ran in a new thread
38
+ # this functions creates a full new process instead
39
+ def forkexec(command, prefix = nil, color = nil)
40
+
41
+ if prefix.nil?
42
+ # TODO: probably pick the command name without args
43
+ prefix = 'unknown'
44
+ end
45
+
46
+ if color.nil?
47
+ color = :cyan
48
+ end
49
+
50
+ Process.fork {
51
+ `#{command}` || raise(command + ' failed')
52
+ }
53
+
54
+ end
55
+
37
56
  end
@@ -43,4 +43,20 @@ module Preconditions
43
43
  raise('Could not find unison binary in path. Please install it, e.g. using "brew install unison"')
44
44
  end
45
45
  end
46
- end
46
+
47
+ def self.unox_available
48
+ if (find_executable0 'unison-fsmonitor').nil?
49
+ cmd1 = 'curl "https://raw.githubusercontent.com/hnsl/unox/master/unox.py" -o "/usr/local/bin/unison-fsmonitor" \
50
+ && chmod +x /usr/local/bin/unison-fsmonitor'
51
+ cmd2 = 'easy_install pip && pip install macfsevents'
52
+ Thor::Shell::Basic.new.say_status 'warning', 'Could not find unison-fsmonitor (for file watching) binary in $PATH. Please install unox before you continue, see https://github.com/hnsl/unox.', :yellow
53
+ if Thor::Shell::Basic.new.yes?('Shall I install unison-fsmonitor for you?')
54
+ `#{cmd1}`
55
+ Thor::Shell::Basic.new.say_status 'ok','install macfsevents using pip', :yellow
56
+ `#{cmd2}`
57
+ else
58
+ raise("Please install it, see https://github.com/hnsl/unox, or simply run :\n #{cmd1} && #{cmd2}")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -5,7 +5,7 @@ require 'docker-sync/sync_process'
5
5
  require 'docker-sync/execution'
6
6
  require 'yaml'
7
7
 
8
- module Docker_Rsync
8
+ module Docker_sync
9
9
  class SyncManager
10
10
  include Thor::Shell
11
11
 
@@ -79,7 +79,9 @@ module Docker_Rsync
79
79
  end
80
80
 
81
81
  def validate_sync_config(name, sync_config)
82
- %w[src dest sync_host_port].each do |key|
82
+ config_mandatory = %w[src dest]
83
+ config_mandatory.push('sync_host_port') unless sync_config['sync_strategy'] == 'unison' #TODO: Implement autodisovery for other strategies
84
+ config_mandatory.each do |key|
83
85
  raise ("#{name} does not have #{key} condiguration value set - this is mandatory") unless sync_config.key?(key)
84
86
  end
85
87
  end
@@ -123,7 +125,12 @@ module Docker_Rsync
123
125
  def join_threads
124
126
  begin
125
127
  @sync_processes.each do |sync_process|
126
- sync_process.watch_thread.join unless sync_process.watch_thread.nil?
128
+ if sync_process.watch_thread
129
+ sync_process.watch_thread.join
130
+ end
131
+ if sync_process.watch_fork
132
+ Process.wait(sync_process.watch_fork)
133
+ end
127
134
  end
128
135
 
129
136
  rescue SystemExit, Interrupt
@@ -1,11 +1,12 @@
1
1
  require 'thor/shell'
2
2
  # noinspection RubyResolve
3
3
  require 'docker-sync/sync_strategy/rsync'
4
+ require 'docker-sync/sync_strategy/unison-onesided'
4
5
  require 'docker-sync/sync_strategy/unison'
5
- require 'docker-sync/sync_strategy/unison-dualside'
6
6
  # noinspection RubyResolve
7
7
  require 'docker-sync/watch_strategy/fswatch'
8
8
  require 'docker-sync/watch_strategy/dummy'
9
+ require 'docker-sync/watch_strategy/unison'
9
10
 
10
11
  module Docker_Sync
11
12
  class SyncProcess
@@ -35,10 +36,10 @@ module Docker_Sync
35
36
  case @options['sync_strategy']
36
37
  when 'rsync'
37
38
  @sync_strategy = Docker_Sync::SyncStrategy::Rsync.new(@sync_name, @options)
39
+ when 'unison-onesided'
40
+ @sync_strategy = Docker_Sync::SyncStrategy::Unison_Onesided.new(@sync_name, @options)
38
41
  when 'unison'
39
42
  @sync_strategy = Docker_Sync::SyncStrategy::Unison.new(@sync_name, @options)
40
- when 'unison-dualside'
41
- @sync_strategy = Docker_Sync::SyncStrategy::Unison_DualSide.new(@sync_name, @options)
42
43
  else
43
44
  @sync_strategy = Docker_Sync::SyncStrategy::Rsync.new(@sync_name, @options)
44
45
  end
@@ -54,11 +55,17 @@ module Docker_Sync
54
55
  @watch_strategy = Docker_Sync::WatchStrategy::Fswatch.new(@sync_name, @options)
55
56
  when 'disable','dummy'
56
57
  @watch_strategy = Docker_Sync::WatchStrategy::Dummy.new(@sync_name, @options)
58
+ when 'unison'
59
+ @watch_strategy = Docker_Sync::WatchStrategy::Unison.new(@sync_name, @options)
57
60
  else
58
61
  @watch_strategy = Docker_Sync::WatchStrategy::Fswatch.new(@sync_name, @options)
59
62
  end
60
63
  else
61
- @watch_strategy = Docker_Sync::WatchStrategy::Fswatch.new(@sync_name, @options)
64
+ if @options['sync_strategy'] == 'unison'
65
+ @watch_strategy = Docker_Sync::WatchStrategy::Unison.new(@sync_name, @options)
66
+ else
67
+ @watch_strategy = Docker_Sync::WatchStrategy::Fswatch.new(@sync_name, @options)
68
+ end
62
69
  end
63
70
  end
64
71
 
@@ -90,6 +97,10 @@ module Docker_Sync
90
97
  @watch_strategy.run
91
98
  end
92
99
 
100
+ def watch_fork
101
+ return @watch_strategy.watch_fork
102
+ end
103
+
93
104
  def watch_thread
94
105
  return @watch_strategy.watch_thread
95
106
  end
@@ -87,17 +87,17 @@ module Docker_Sync
87
87
  say_status 'ok', 'Starting rsync', :white
88
88
  container_name = get_container_name
89
89
  volume_name = get_volume_name
90
- running = `docker ps --filter 'status=running' --filter 'name=#{container_name}' | grep #{container_name}`
90
+ running = `docker ps --filter 'status=running' --filter 'name=#{container_name}' | sed -E -n 's/.*\\s(.*)$/\\1/p' | grep '^#{container_name}$'`
91
91
  if running == '' # container is yet not running
92
92
  say_status 'ok', "#{container_name} container not running", :white if @options['verbose']
93
- exists = `docker ps --filter "status=exited" --filter "name=#{container_name}" | grep #{container_name}`
93
+ exists = `docker ps --filter "status=exited" --filter "name=#{container_name}" | sed -E -n 's/.*\\s(.*)$/\\1/p' | grep '^#{container_name}$'`
94
94
  if exists == '' # container has yet not been created
95
95
  say_status 'ok', "creating #{container_name} container", :white if @options['verbose']
96
96
 
97
97
  user_mapping = get_user_mapping
98
98
  group_mapping = get_group_mapping
99
99
 
100
- cmd = "docker run -p '#{@options['sync_host_port']}:873' -v #{volume_name}:#{@options['dest']} #{user_mapping} #{group_mapping} -e VOLUME=#{@options['dest']} --name #{container_name} -d #{@docker_image}"
100
+ cmd = "docker run -p '#{@options['sync_host_port']}:873' -v #{volume_name}:#{@options['dest']} #{user_mapping} #{group_mapping} -e VOLUME=#{@options['dest']} -e TZ=${TZ-`readlink /etc/localtime | sed -e 's,/usr/share/zoneinfo/,,'`} --name #{container_name} -d #{@docker_image}"
101
101
  else # container already created, just start / reuse it
102
102
  say_status 'ok', "starting #{container_name} container", :white if @options['verbose']
103
103
  cmd = "docker start #{container_name}"
@@ -1,18 +1,16 @@
1
1
  require 'thor/shell'
2
2
  require 'docker-sync/preconditions'
3
3
  require 'open3'
4
- require 'socket'
5
4
  require 'terminal-notifier'
6
5
 
7
6
  module Docker_Sync
8
7
  module SyncStrategy
9
- class Unison_DualSide
8
+ class Unison_Onesided
10
9
  include Thor::Shell
11
10
 
12
11
  @options
13
12
  @sync_name
14
13
  @watch_thread
15
- @local_server_pid
16
14
  UNISON_CONTAINER_PORT = '5000'
17
15
  def initialize(sync_name, options)
18
16
  @sync_name = sync_name
@@ -21,7 +19,7 @@ module Docker_Sync
21
19
  if @options.key?('image')
22
20
  @docker_image = @options['image']
23
21
  else
24
- @docker_image = 'eugenmayer/unison:dualside'
22
+ @docker_image = 'eugenmayer/unison:onesided'
25
23
  end
26
24
  begin
27
25
  Preconditions::unison_available
@@ -34,7 +32,6 @@ module Docker_Sync
34
32
 
35
33
  def run
36
34
  start_container
37
- start_local_server
38
35
  sync
39
36
  end
40
37
 
@@ -68,16 +65,11 @@ module Docker_Sync
68
65
  args.push(@options['src'])
69
66
  args.push('-auto')
70
67
  args.push('-batch')
71
- args.push('-owner') if @options['sync_userid'] == 'from_host'
72
- args.push('-numericids') if @options['sync_userid'] == 'from_host'
73
68
  args.push(@options['sync_args']) if @options.key?('sync_args')
74
69
  args.push("socket://#{@options['sync_host_ip']}:#{@options['sync_host_port']}/")
75
70
  args.push('-debug all') if @options['verbose']
76
- if @options.key?('sync_user') || @options.key?('sync_group') || @options.key?('sync_groupid')
77
- raise('Unison does not support sync_user, sync_group, sync_groupid - please use rsync if you need that')
78
- end
79
- if @options.key?('sync_userid') && @options['sync_userid'] != 'from_host'
80
- raise('Unison does not support sync_userid with a parameter different than \'from_host\'')
71
+ if @options.key?('sync_user') || @options.key?('sync_group') || @options.key?('sync_groupid') || @options.key?('sync_userid')
72
+ raise('Unison does not support sync_user, sync_group, sync_groupid or sync_userid - please use rsync if you need that')
81
73
  end
82
74
  return args
83
75
  end
@@ -86,33 +78,13 @@ module Docker_Sync
86
78
  say_status 'ok', 'Starting unison', :white
87
79
  container_name = get_container_name
88
80
  volume_name = get_volume_name
89
- env = {}
90
-
91
- env['ENABLE_WATCH'] = 'true'
92
- # Excludes for fswatch and unison uses the same value both in the host and in the container
93
- env['FSWATCH_EXCLUDES'] = @options['watch_excludes'].map { |pattern| "--exclude='#{pattern}'" }.join(' ') if @options.key?('watch_excludes')
94
- env['UNISON_EXCLUDES'] = @options['sync_excludes'].map { |pattern| "-ignore='Path #{pattern}'" }.join(' ') if @options.key?('sync_excludes')
95
- # Specify the IP of the host to call the host unison server from the container
96
- env['HOST_IP'] = get_host_ip
97
- env['UNISON_HOST_PORT'] = @options['unison-dualside_host_server_port']
98
-
99
- if @options['sync_userid'] == 'from_host'
100
- env['UNISON_DIR_OWNER'] = Process.uid
101
- end
102
-
103
- additional_docker_env = env.map{ |key,value| "-e #{key}=\"#{value}\"" }.join(' ')
104
- running = `docker ps --filter 'status=running' --filter 'name=#{container_name}' | grep #{container_name}`
81
+ running = `docker ps --filter 'status=running' --filter 'name=#{container_name}' | sed -E -n 's/.*\\s(.*)$/\\1/p' | grep '^#{container_name}$'`
105
82
  if running == ''
106
83
  say_status 'ok', "#{container_name} container not running", :white if @options['verbose']
107
- exists = `docker ps --filter "status=exited" --filter "name=#{container_name}" | grep #{container_name}`
84
+ exists = `docker ps --filter "status=exited" --filter "name=#{container_name}" | sed -E -n 's/.*\\s(.*)$/\\1/p' | grep '^#{container_name}$'`
108
85
  if exists == ''
109
86
  say_status 'ok', "creating #{container_name} container", :white if @options['verbose']
110
- cmd = "docker run -p '#{@options['sync_host_port']}:#{UNISON_CONTAINER_PORT}' \
111
- -v #{volume_name}:#{@options['dest']} \
112
- -e UNISON_DIR=#{@options['dest']} \
113
- #{additional_docker_env} \
114
- --name #{container_name} \
115
- -d #{@docker_image}"
87
+ cmd = "docker run -p '#{@options['sync_host_port']}:#{UNISON_CONTAINER_PORT}' -v #{volume_name}:#{@options['dest']} -e UNISON_DIR=#{@options['dest']} -e TZ=${TZ-`readlink /etc/localtime | sed -e 's,/usr/share/zoneinfo/,,'`} --name #{container_name} -d #{@docker_image}"
116
88
  else
117
89
  say_status 'ok', "starting #{container_name} container", :white if @options['verbose']
118
90
  cmd = "docker start #{container_name}"
@@ -124,48 +96,11 @@ module Docker_Sync
124
96
  end
125
97
  say_status 'ok', "starting initial sync of #{container_name}", :white if @options['verbose']
126
98
  # this sleep is needed since the container could be not started
127
- sleep 5 # TODO: replace with unison -testserver
99
+ sleep 1
128
100
  sync
129
101
  say_status 'success', 'Unison server started', :green
130
102
  end
131
103
 
132
- # Start an unison server on the host
133
- def start_local_server
134
- say_status 'ok', 'Starting local unison server', :white
135
-
136
- if not @options.key?('unison-dualside_host_server_port')
137
- raise('Missing unison-dualside_host_server_port option. In order to get files synced back automatically from the
138
- container, you must specify the port of the local unison server.')
139
- end
140
- cmd = "unison -socket #{@options['unison-dualside_host_server_port']}"
141
- say_status 'command', cmd, :white if @options['verbose']
142
-
143
- # Store the pid of the local unison server, to kill it when docker-sync stops
144
- @local_server_pid = Process.fork do
145
- # Run the local unison server in the source folder
146
- Dir.chdir(@options['src']){
147
- `#{cmd}` || raise('Start of local unison server failed')
148
- }
149
- end
150
- end
151
-
152
- # Try to guess the IP of the host to call the unison server from the container
153
- # Or use the value specified in the config option
154
- def get_host_ip
155
- if @options['unison-dualside_host_ip'] != 'auto' && @options.key?('unison-dualside_host_ip')
156
- host_ip = @options['host_ip']
157
- elsif @options['unison-dualside_host_ip'] == 'auto' || (not @options.key?('unison-dualside_host_ip'))
158
- host_ip = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
159
- end
160
- return host_ip
161
- end
162
-
163
- # Kill the local unison server
164
- def stop_local_server
165
- Process.kill "TERM", @local_server_pid
166
- Process.wait @local_server_pid
167
- end
168
-
169
104
  def get_container_name
170
105
  return "#{@sync_name}"
171
106
  end
@@ -192,7 +127,6 @@ module Docker_Sync
192
127
  say_status 'ok', "Stopping sync container #{get_container_name}"
193
128
  begin
194
129
  stop_container
195
- stop_local_server
196
130
  rescue Exception => e
197
131
  say_status 'error', "Stopping failed of #{get_container_name}:", :red
198
132
  puts e.message
@@ -1,28 +1,33 @@
1
1
  require 'thor/shell'
2
2
  require 'docker-sync/preconditions'
3
+ require 'docker-sync/execution'
3
4
  require 'open3'
5
+ require 'socket'
4
6
  require 'terminal-notifier'
5
7
 
6
8
  module Docker_Sync
7
9
  module SyncStrategy
8
10
  class Unison
9
11
  include Thor::Shell
12
+ include Execution
10
13
 
11
14
  @options
12
15
  @sync_name
13
16
  @watch_thread
17
+ @local_server_pid
14
18
  UNISON_CONTAINER_PORT = '5000'
15
19
  def initialize(sync_name, options)
16
- @sync_name = sync_name
17
20
  @options = options
21
+ @sync_name = sync_name
18
22
  # if a custom image is set, apply it
19
23
  if @options.key?('image')
20
24
  @docker_image = @options['image']
21
25
  else
22
- @docker_image = 'eugenmayer/unison'
26
+ @docker_image = 'eugenmayer/unison:unox'
23
27
  end
24
28
  begin
25
29
  Preconditions::unison_available
30
+ Preconditions::unox_available
26
31
  rescue Exception => e
27
32
  say_status 'error', "#{@sync_name} has been configured to sync with unison, but no unison available", :red
28
33
  say_status 'error', e.message, :red
@@ -31,10 +36,41 @@ module Docker_Sync
31
36
  end
32
37
 
33
38
  def run
39
+ increase_watcher_limit if @options.key?('max_inotify_watches')
34
40
  start_container
35
41
  sync
36
42
  end
37
43
 
44
+ def increase_watcher_limit
45
+ current_max_files_per_proc = `sysctl kern.maxfilesperproc | awk '{print $2}'`
46
+ if current_max_files_per_proc.to_f < @options['max_inotify_watches']
47
+ cmd = 'sudo sysctl -w kern.maxfilesperproc=' + @options['max_inotify_watches'].to_s
48
+ say_status 'command', cmd, :white
49
+ `#{cmd}` || raise('Unable to increase maxfilesperproc')
50
+ else
51
+ say_status 'command', 'Current maxfilesperproc set to ' + current_max_files_per_proc.to_s, :white
52
+ end
53
+ current_max_files = `sysctl kern.maxfiles | awk '{print $2}'`
54
+ if current_max_files.to_f < @options['max_inotify_watches']
55
+ cmd = 'sudo sysctl -w kern.maxfiles=' + @options['max_inotify_watches'].to_s
56
+ say_status 'command', cmd, :white
57
+ `#{cmd}` || raise('Unable to increase maxfiles')
58
+ else
59
+ say_status 'command', 'Current maxfiles set to ' + current_max_files.to_s, :white
60
+ end
61
+ end
62
+
63
+ def watch
64
+ args = sync_options
65
+ args.push("-repeat watch")
66
+ cmd = ''
67
+ cmd = cmd + 'ulimit -n ' + @options['max_inotify_watches'].to_s + ' && ' if @options.key?('max_inotify_watches')
68
+ cmd = cmd + 'unison ' + args.join(' ')
69
+
70
+ say_status 'command', cmd, :white if @options['verbose']
71
+ forkexec(cmd, "Sync #{@sync_name}", :blue)
72
+ end
73
+
38
74
  def sync
39
75
  args = sync_options
40
76
  cmd = 'unison ' + args.join(' ')
@@ -47,7 +83,7 @@ module Docker_Sync
47
83
  say_status 'message', stderr
48
84
  else
49
85
  TerminalNotifier.notify(
50
- "Synced #{@options['src']}", :title => @sync_name
86
+ "Synced #{@options['src']}", :title => @sync_name
51
87
  ) if @options['notify_terminal']
52
88
  say_status 'ok', "Synced #{@options['src']}", :white
53
89
  if @options['verbose']
@@ -66,10 +102,11 @@ module Docker_Sync
66
102
  args.push('-auto')
67
103
  args.push('-batch')
68
104
  args.push(@options['sync_args']) if @options.key?('sync_args')
69
- args.push("socket://#{@options['sync_host_ip']}:#{@options['sync_host_port']}/")
70
- args.push('-debug all') if @options['verbose']
71
- if @options.key?('sync_user') || @options.key?('sync_group') || @options.key?('sync_groupid') || @options.key?('sync_userid')
72
- raise('Unison does not support sync_user, sync_group, sync_groupid or sync_userid - please use rsync if you need that')
105
+ sync_host_port = get_host_port(get_container_name, UNISON_CONTAINER_PORT)
106
+ args.push("socket://#{@options['sync_host_ip']}:#{sync_host_port}")
107
+
108
+ if @options.key?('sync_group') || @options.key?('sync_groupid')
109
+ raise('Unison does not support sync_user, sync_group, sync_groupid - please use rsync if you need that')
73
110
  end
74
111
  return args
75
112
  end
@@ -78,30 +115,62 @@ module Docker_Sync
78
115
  say_status 'ok', 'Starting unison', :white
79
116
  container_name = get_container_name
80
117
  volume_name = get_volume_name
118
+ env = {}
119
+
120
+ env['UNISON_EXCLUDES'] = @options['sync_excludes'].map { |pattern| "-ignore='Path #{pattern}'" }.join(' ') if @options.key?('sync_excludes')
121
+ env['UNISON_OWNER'] = @options['sync_user'] if @options.key?('sync_user')
122
+ env['MAX_INOTIFY_WATCHES'] = @options['max_inotify_watches'] if @options.key?('max_inotify_watches')
123
+ if @options['sync_userid'] == 'from_host'
124
+ env['UNISON_OWNER_UID'] = Process.uid
125
+ else
126
+ env['UNISON_OWNER_UID'] = @options['sync_userid'] if @options.key?('sync_userid')
127
+ end
81
128
 
82
- running = `docker ps --filter 'status=running' --filter 'name=#{container_name}' | grep #{container_name}`
129
+ additional_docker_env = env.map{ |key,value| "-e #{key}=\"#{value}\"" }.join(' ')
130
+ running = `docker ps --filter 'status=running' --filter 'name=#{container_name}' | sed -E -n 's/.*\\s(.*)$/\\1/p' | grep '^#{container_name}$'`
83
131
  if running == ''
84
132
  say_status 'ok', "#{container_name} container not running", :white if @options['verbose']
85
- exists = `docker ps --filter "status=exited" --filter "name=#{container_name}" | grep #{container_name}`
133
+ exists = `docker ps --filter "status=exited" --filter "name=#{container_name}" | sed -E -n 's/.*\\s(.*)$/\\1/p' | grep '^#{container_name}$'`
86
134
  if exists == ''
87
135
  say_status 'ok', "creating #{container_name} container", :white if @options['verbose']
88
- cmd = "docker run -p '#{@options['sync_host_port']}:#{UNISON_CONTAINER_PORT}' -v #{volume_name}:#{@options['dest']} -e UNISON_DIR=#{@options['dest']} --name #{container_name} -d #{@docker_image}"
136
+ run_privileged = '--privileged' if @options.key?('max_inotify_watches') #TODO: replace by the minimum capabilities required
137
+ cmd = "docker run -p '127.0.0.1::#{UNISON_CONTAINER_PORT}' \
138
+ -v #{volume_name}:#{@options['dest']} \
139
+ -e UNISON_DIR=#{@options['dest']} \
140
+ -e TZ=${TZ-`readlink /etc/localtime | sed -e 's,/usr/share/zoneinfo/,,'`} \
141
+ #{additional_docker_env} \
142
+ #{run_privileged} \
143
+ --name #{container_name} \
144
+ -d #{@docker_image}"
89
145
  else
90
146
  say_status 'ok', "starting #{container_name} container", :white if @options['verbose']
91
- cmd = "docker start #{container_name}"
147
+ cmd = "docker start #{container_name} && docker exec #{container_name} supervisorctl restart unison"
92
148
  end
93
- say_status 'command', cmd, :white if @options['verbose']
94
- `#{cmd}` || raise('Start failed')
95
149
  else
96
- say_status 'ok', "#{container_name} container still running", :blue
150
+ say_status 'ok', "#{container_name} container still running, restarting unison in container", :blue
151
+ cmd = "docker exec #{container_name} supervisorctl restart unison"
97
152
  end
153
+ say_status 'command', cmd, :white if @options['verbose']
154
+ `#{cmd}` || raise('Start failed')
98
155
  say_status 'ok', "starting initial sync of #{container_name}", :white if @options['verbose']
99
156
  # this sleep is needed since the container could be not started
100
- sleep 1
157
+ sleep 5 # TODO: replace with unison -testserver
101
158
  sync
102
159
  say_status 'success', 'Unison server started', :green
103
160
  end
104
161
 
162
+ def get_host_port(container_name, container_port)
163
+ cmd = 'docker inspect --format=" {{ .NetworkSettings.Ports }} " ' + container_name + ' | sed "s/.*map\[' + container_port + '[^ ]\+\s\([0-9]\+\).*/\1/"'
164
+ say_status 'command', cmd, :white if @options['verbose']
165
+ stdout, stderr, exit_status = Open3.capture3(cmd)
166
+ if not exit_status.success?
167
+ say_status 'command', cmd
168
+ say_status 'error', "Error getting mapped port, exit code #{$?.exitstatus}", :red
169
+ say_status 'message', stderr
170
+ end
171
+ return stdout.gsub("\n",'')
172
+ end
173
+
105
174
  def get_container_name
106
175
  return "#{@sync_name}"
107
176
  end
@@ -18,6 +18,8 @@ class UpdateChecker
18
18
  return
19
19
  end
20
20
  check_rsync_image unless DockerSyncConfig::is_first_run # do not check the image if its the first run - since this it will be downloaded anyway
21
+ check_unison_onesided_image unless DockerSyncConfig::is_first_run
22
+ check_unison_image unless DockerSyncConfig::is_first_run
21
23
  check_and_warn(@config['update_enforce'])
22
24
  end
23
25
 
@@ -44,6 +46,30 @@ class UpdateChecker
44
46
  say_status 'success','Image is (now) up to date'
45
47
  end
46
48
 
49
+ def check_unison_image
50
+ say_status 'ok','Checking if a newer unison image is available'
51
+
52
+ if system("docker pull eugenmayer/unison:unox | grep 'Downloaded newer image for'")
53
+ say_status 'warning', 'Downloaded newer image for unison', :red
54
+ say_status 'warning', 'Please use "docker-sync clean" before you start docker-sync again', :red
55
+
56
+ exit 0
57
+ end
58
+ say_status 'success','Image is (now) up to date'
59
+ end
60
+
61
+ def check_unison_onesided_image
62
+ say_status 'ok','Checking if a newer unison:onesided image is available'
63
+
64
+ if system("docker pull eugenmayer/unison:onesided | grep 'Downloaded newer image for'")
65
+ say_status 'warning', 'Downloaded newer image for unison:onesided', :red
66
+ say_status 'warning', 'Please use "docker-sync clean" before you start docker-sync again', :red
67
+
68
+ exit 0
69
+ end
70
+ say_status 'success','Image is (now) up to date'
71
+ end
72
+
47
73
  def get_current_version
48
74
  path = File.expand_path('../../../', __FILE__)
49
75
  return File.read("#{path}/VERSION")
@@ -0,0 +1,59 @@
1
+ require 'gem_update_checker'
2
+ require 'thor/actions'
3
+ require 'docker-sync/config'
4
+
5
+ class UpgradeChecker
6
+ include Thor::Shell
7
+ @config
8
+ def initialize
9
+ @config = DockerSyncConfig::global_config
10
+ end
11
+
12
+ def run
13
+ unless should_run
14
+ return
15
+ end
16
+ check_and_warn
17
+ end
18
+
19
+ def last_upgraded_version
20
+ @config['upgrade_status'] || ''
21
+ end
22
+
23
+ def should_run
24
+ # get the update_status which is the version of the update hook which has been run already
25
+ upgrade_status = last_upgraded_version
26
+ if upgrade_status == '' || Gem::Version.new(upgrade_status) < Gem::Version.new(get_current_version) # thats how we compare the version
27
+ return true
28
+ end
29
+
30
+ return false
31
+ end
32
+
33
+
34
+ def get_current_version
35
+ path = File.expand_path('../../../', __FILE__)
36
+ return File.read("#{path}/VERSION")
37
+ end
38
+
39
+ def docker_sync_update_check
40
+ gem_name = 'docker-sync'
41
+ current_version = get_current_version
42
+ checker = GemUpdateChecker::Client.new(gem_name, current_version)
43
+ return checker
44
+ end
45
+
46
+ def check_and_warn
47
+ # this is the upgrade hook for the unison-unox introduction / rename of unison
48
+ if Gem::Version.new(last_upgraded_version) < Gem::Version.new('0.1.0')
49
+ Thor::Shell::Basic.new.say_status 'warning', 'Please be aware that with the strategy "unison" is now called unison-onesided and you might need to migrate. See https://github.com/EugenMayer/docker-sync/wiki/Migration-Guide for more informations', :red
50
+ unless Thor::Shell::Basic.new.yes?('Shall we continue?')
51
+ exit 1
52
+ end
53
+ end
54
+
55
+ # update the upgrade_status
56
+ @config['upgrade_status'] = "#{get_current_version}"
57
+ DockerSyncConfig::global_config_save(@config)
58
+ end
59
+ end
@@ -0,0 +1,53 @@
1
+ require 'thor/shell'
2
+ require 'docker-sync/execution'
3
+ require 'docker-sync/preconditions'
4
+ require 'docker-sync/sync_strategy/unison'
5
+
6
+ module Docker_Sync
7
+ module WatchStrategy
8
+ class Unison
9
+ include Execution
10
+
11
+ @options
12
+ @sync_name
13
+ @watch_fork
14
+
15
+ def initialize(sync_name, options)
16
+ @options = options
17
+ @sync_name = sync_name
18
+ @watch_fork = nil
19
+ # instantiate the sync task to easily access all common parameters between
20
+ # unison sync and watch
21
+ # basically unison watch is the command with the additionnal -repeat watch option
22
+ # note: this doesn't run a sync
23
+ @unison = Docker_Sync::SyncStrategy::Unison.new(@sync_name, @options)
24
+ end
25
+
26
+ def run
27
+ @watch_fork = @unison.watch
28
+ end
29
+
30
+ def stop
31
+ Process.kill "TERM", @watch_fork
32
+ Process.wait @watch_fork
33
+ end
34
+
35
+ def clean
36
+ end
37
+
38
+ def watch
39
+ end
40
+
41
+ def watch_options
42
+ end
43
+
44
+ def watch_fork
45
+ return @watch_fork
46
+ end
47
+
48
+ def watch_thread
49
+ return nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -2,6 +2,7 @@ require 'docker-sync/sync_manager'
2
2
  require 'docker-sync/config'
3
3
  require 'docker-sync/preconditions'
4
4
  require 'docker-sync/update_check'
5
+ require 'docker-sync/upgrade_check'
5
6
  require 'docker/compose'
6
7
  require 'docker-sync/compose'
7
8
  class Stack < Thor
@@ -15,6 +16,9 @@ class Stack < Thor
15
16
  updates = UpdateChecker.new
16
17
  updates.run
17
18
 
19
+ upgrades = UpgradeChecker.new
20
+ upgrades.run
21
+
18
22
  begin
19
23
  Preconditions::check_all_preconditions
20
24
  rescue Exception => e
@@ -33,7 +37,7 @@ class Stack < Thor
33
37
  end
34
38
  end
35
39
 
36
- @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
40
+ @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
37
41
  @sync_manager.run(options[:sync_name])
38
42
  global_options = @sync_manager.global_options
39
43
  @compose_manager = ComposeManager.new(global_options)
@@ -76,7 +80,7 @@ class Stack < Thor
76
80
  return
77
81
  end
78
82
  end
79
- @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
83
+ @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
80
84
  global_options = @sync_manager.global_options
81
85
  # shutdown compose first
82
86
  @compose_manager = ComposeManager.new(global_options)
@@ -2,6 +2,7 @@ require 'docker-sync/sync_manager'
2
2
  require 'docker-sync/config'
3
3
  require 'docker-sync/preconditions'
4
4
  require 'docker-sync/update_check'
5
+ require 'docker-sync/upgrade_check'
5
6
 
6
7
  class Sync < Thor
7
8
 
@@ -13,7 +14,8 @@ class Sync < Thor
13
14
  # do run update check in the start command only
14
15
  updates = UpdateChecker.new
15
16
  updates.run
16
-
17
+ upgrades = UpgradeChecker.new
18
+ upgrades.run
17
19
  begin
18
20
  Preconditions::check_all_preconditions
19
21
  rescue Exception => e
@@ -31,7 +33,7 @@ class Sync < Thor
31
33
  return
32
34
  end
33
35
  end
34
- @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
36
+ @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
35
37
  @sync_manager.run(options[:sync_name])
36
38
  @sync_manager.join_threads
37
39
  end
@@ -55,7 +57,7 @@ class Sync < Thor
55
57
  return
56
58
  end
57
59
  end
58
- @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
60
+ @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
59
61
  @sync_manager.sync(options[:sync_name])
60
62
  end
61
63
 
@@ -78,7 +80,7 @@ class Sync < Thor
78
80
  return
79
81
  end
80
82
  end
81
- @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
83
+ @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
82
84
  @sync_manager.clean(options[:sync_name])
83
85
  say_status 'success', 'Finished cleanup. Removed stopped, removed sync container and removed there volumes', :green
84
86
  end
@@ -105,12 +107,18 @@ class Sync < Thor
105
107
  end
106
108
 
107
109
  say_status 'ok',"Found configuration at #{config_path}"
108
- @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
110
+ @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
109
111
  @sync_manager.get_sync_points.each do |name, config|
110
112
  say_status name, "On address #{config['sync_host_ip']}:#{config['sync_host_port']}",:white unless options['verbose']
111
113
  puts "\n---------------[#{name}] #{config['sync_host_ip']}:#{config['sync_host_port']} ---------------\n" if options['verbose']
112
114
  print_table(config) if options['verbose']
113
115
  end
114
116
  end
117
+ desc 'start', 'Start all sync configurations in this project'
118
+ def upgrade
119
+ # do run update check in the start command only
120
+ upgrades = UpgradeChecker.new
121
+ upgrades.run
122
+ end
115
123
 
116
124
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugen Mayer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-25 00:00:00.000000000 Z
11
+ date: 2016-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -98,11 +98,13 @@ files:
98
98
  - lib/docker-sync/sync_manager.rb
99
99
  - lib/docker-sync/sync_process.rb
100
100
  - lib/docker-sync/sync_strategy/rsync.rb
101
- - lib/docker-sync/sync_strategy/unison-dualside.rb
101
+ - lib/docker-sync/sync_strategy/unison-onesided.rb
102
102
  - lib/docker-sync/sync_strategy/unison.rb
103
103
  - lib/docker-sync/update_check.rb
104
+ - lib/docker-sync/upgrade_check.rb
104
105
  - lib/docker-sync/watch_strategy/dummy.rb
105
106
  - lib/docker-sync/watch_strategy/fswatch.rb
107
+ - lib/docker-sync/watch_strategy/unison.rb
106
108
  - tasks/stack/stack.thor
107
109
  - tasks/sync/sync.thor
108
110
  homepage: https://github.com/EugenMayer/docker_sync
@@ -117,7 +119,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
119
  requirements:
118
120
  - - ">="
119
121
  - !ruby/object:Gem::Version
120
- version: '0'
122
+ version: '2.0'
121
123
  required_rubygems_version: !ruby/object:Gem::Requirement
122
124
  requirements:
123
125
  - - ">="