docker-sync 0.2.3 → 0.3.0

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.
@@ -1,10 +1,12 @@
1
+ require 'docker-sync'
1
2
  require 'docker-sync/sync_manager'
2
- require 'docker-sync/config'
3
- require 'docker-sync/preconditions'
3
+ require 'docker-sync/preconditions/strategy'
4
4
  require 'docker-sync/update_check'
5
5
  require 'docker-sync/upgrade_check'
6
6
  require 'daemons'
7
7
  require 'fileutils'
8
+ require 'docker-sync/config/project_config'
9
+ require 'timeout'
8
10
 
9
11
  class Sync < Thor
10
12
 
@@ -27,11 +29,11 @@ class Sync < Thor
27
29
  def start
28
30
  print_version if options[:version]
29
31
  # do run update check in the start command only
30
- UpdateChecker.new().run
31
- UpgradeChecker.new().run
32
+ UpdateChecker.new.run
33
+ UpgradeChecker.new.run
32
34
 
33
- config_path = config_preconditions # Preconditions and Define config_path from shared method
34
- @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
35
+ config = config_preconditions
36
+ @sync_manager = Docker_sync::SyncManager.new(config: config)
35
37
 
36
38
  start_dir = Dir.pwd # Set start_dir variable to be equal to pre-daemonized folder, since daemonizing will change dir to '/'
37
39
  if options['daemon']
@@ -52,18 +54,17 @@ class Sync < Thor
52
54
  def stop
53
55
  print_version if options[:version]
54
56
 
55
- config_path = config_preconditions
56
- sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
57
+ config = config_preconditions
58
+ sync_manager = Docker_sync::SyncManager.new(config: config)
57
59
 
58
60
  begin
59
61
  pid = File.read("#{options['dir']}/#{options['app_name']}.pid") # Read PID from PIDFILE created by Daemons
60
62
  Process.kill(:INT, -(Process.getpgid(pid.to_i))) # Send INT signal to group PID, which means INT will be sent to all sub-processes and Threads spawned by docker-sync
61
- say_status 'shutdown', 'Background dsync has been stopped'
63
+ wait_for_process_termination(pid.to_i)
62
64
  rescue Errno::ESRCH, Errno::ENOENT => e
63
65
  say_status 'error', e.message, :red # Rescue incase PIDFILE does not exist or there is no process with such PID
64
- say_status(
65
- 'error', 'Check if your PIDFILE and process with such PID exists', :red
66
- )
66
+ say_status 'error', 'Check if your PIDFILE and process with such PID exists', :red
67
+ exit(69) # EX_UNAVAILABLE (see `man sysexits` or `/usr/include/sysexits.h`)
67
68
  end
68
69
  end
69
70
 
@@ -71,9 +72,9 @@ class Sync < Thor
71
72
  def sync
72
73
  print_version if options[:version]
73
74
 
74
- config_path = config_preconditions # Preconditions and Define config_path from shared method
75
+ config = config_preconditions
75
76
 
76
- @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
77
+ @sync_manager = Docker_sync::SyncManager.new(config: config)
77
78
  @sync_manager.sync(options[:sync_name])
78
79
  end
79
80
 
@@ -81,7 +82,7 @@ class Sync < Thor
81
82
  def clean
82
83
  print_version if options[:version]
83
84
 
84
- config_path = config_preconditions # Preconditions and Define config_path from shared method
85
+ config = config_preconditions
85
86
 
86
87
  # Look for any background syncs and stop them if we see them
87
88
  dir = './.docker-sync'
@@ -94,7 +95,7 @@ class Sync < Thor
94
95
  # Remove the .docker-sync directory
95
96
  FileUtils.rm_r dir if File.directory?(dir)
96
97
 
97
- @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
98
+ @sync_manager = Docker_sync::SyncManager.new(config: config)
98
99
  @sync_manager.clean(options[:sync_name])
99
100
  say_status 'success', 'Finished cleanup. Removed stopped, removed sync container and removed their volumes', :green
100
101
  end
@@ -116,10 +117,10 @@ class Sync < Thor
116
117
  def list
117
118
  print_version if options[:version]
118
119
 
119
- config_path = config_preconditions # Preconditions and Define config_path from shared method
120
+ config = config_preconditions
120
121
 
121
122
  say_status 'ok',"Found configuration at #{config_path}"
122
- @sync_manager = Docker_sync::SyncManager.new(:config_path => config_path)
123
+ @sync_manager = Docker_sync::SyncManager.new(config: config)
123
124
  @sync_manager.get_sync_points.each do |name, config|
124
125
  say_status name, "On address #{config['sync_host_ip']}:#{config['sync_host_port']}",:white unless options['verbose']
125
126
  puts "\n---------------[#{name}] #{config['sync_host_ip']}:#{config['sync_host_port']} ---------------\n" if options['verbose']
@@ -130,16 +131,9 @@ class Sync < Thor
130
131
  no_tasks do
131
132
  def config_preconditions # Moved shared preconditions block into separate method to have less/cleaner code
132
133
  begin
133
- Preconditions::check_all_preconditions
134
- rescue Exception => e
135
- say_status 'error', e.message, :red
136
- exit 1
137
- end
138
-
139
- return options[:config] if options[:config]
140
-
141
- begin
142
- DockerSyncConfig::project_config_path
134
+ DockerSync::ProjectConfig.new(config_path: options[:config]).tap do |config|
135
+ DockerSync::Preconditions::Strategy.instance.check_all_preconditions(config)
136
+ end
143
137
  rescue Exception => e
144
138
  say_status 'error', e.message, :red
145
139
  exit 1
@@ -191,5 +185,29 @@ class Sync < Thor
191
185
  pid_file = Daemons::PidFile.find_files(options['dir'], options['app_name']).first || ''
192
186
  File.file?(pid_file) && Daemons::Pid.running?(File.read(pid_file).to_i)
193
187
  end
188
+
189
+ def wait_for_process_termination(pid)
190
+ print 'Waiting for background docker-sync to terminate'
191
+ Timeout::timeout(30) do
192
+ loop do
193
+ if process_dead?(pid)
194
+ puts
195
+ say_status 'shutdown', 'Background docker-sync has been stopped'
196
+ return
197
+ else
198
+ sleep 1
199
+ print '.'
200
+ end
201
+ end
202
+ end
203
+ rescue Timeout::Error
204
+ puts
205
+ say_status 'error', 'Background docker-sync daemon failed to stop within 30 seconds', :red
206
+ exit 70 # EX_SOFTWARE (according to `man sysexits`)
207
+ end
208
+
209
+ def process_dead?(pid)
210
+ !system("ps -p #{pid} > /dev/null")
211
+ end
194
212
  end
195
213
  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.2.3
4
+ version: 0.3.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: 2017-03-27 00:00:00.000000000 Z
11
+ date: 2017-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -124,6 +124,20 @@ dependencies:
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: 1.2.3
127
+ - !ruby/object:Gem::Dependency
128
+ name: os
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
127
141
  description: Sync your code live to docker-containers without losing any performance
128
142
  on OSX
129
143
  email: eugen.mayer@kontextwork.de
@@ -139,11 +153,16 @@ files:
139
153
  - bin/docker-sync
140
154
  - bin/docker-sync-daemon
141
155
  - bin/docker-sync-stack
156
+ - lib/docker-sync.rb
142
157
  - lib/docker-sync/compose.rb
143
- - lib/docker-sync/config.rb
144
- - lib/docker-sync/config_template.rb
158
+ - lib/docker-sync/config/config_locator.rb
159
+ - lib/docker-sync/config/config_serializer.rb
160
+ - lib/docker-sync/config/global_config.rb
161
+ - lib/docker-sync/config/project_config.rb
145
162
  - lib/docker-sync/execution.rb
146
- - lib/docker-sync/preconditions.rb
163
+ - lib/docker-sync/preconditions/preconditions_linux.rb
164
+ - lib/docker-sync/preconditions/preconditions_osx.rb
165
+ - lib/docker-sync/preconditions/strategy.rb
147
166
  - lib/docker-sync/sync_manager.rb
148
167
  - lib/docker-sync/sync_process.rb
149
168
  - lib/docker-sync/sync_strategy/rsync.rb
@@ -1,120 +0,0 @@
1
- require 'pp'
2
- require 'pathname'
3
- require 'yaml'
4
- require 'dotenv'
5
- require 'docker-sync/config_template'
6
-
7
- # this has basically completely reused from Thor::runner.rb - thank you!
8
- module DockerSyncConfig
9
-
10
- def initialize(options)
11
- load_dotenv
12
- end
13
-
14
- def self.load_dotenv
15
- env_file = ENV.fetch('DOCKER_SYNC_ENV_FILE', '.env')
16
- Dotenv.load(env_file)
17
- end
18
-
19
- def self.global_config_location
20
- return File.expand_path('~/.docker-sync-global.yml')
21
- end
22
-
23
- def self.is_first_run
24
- global_config_path = global_config_location
25
- return !File.exist?(global_config_path)
26
- end
27
-
28
- def self.global_config
29
- global_config_path = global_config_location
30
- date = DateTime.new(2001, 1, 1) #paste
31
- # noinspection RubyStringKeysInHashInspection
32
- defaults = {'update_check'=>true, 'update_last_check' => date.iso8601(9), 'update_enforce' => true}
33
- if File.exist?(global_config_path)
34
- config = ConfigTemplate::interpolate_config_file(global_config_path)
35
- config = defaults.merge(config)
36
- return config
37
- else
38
- return defaults
39
- end
40
- end
41
-
42
- def self.global_config_save(config)
43
- global_config_path = global_config_location
44
- File.open(global_config_path, 'w') {|f| f.write config.to_yaml }
45
- end
46
-
47
-
48
- def self.project_required_config_version
49
- return '2'
50
- end
51
-
52
- def self.project_ensure_configuration_version_compatibility(config)
53
- return false unless config.key?('version')
54
- return false if config['version'].to_s != project_required_config_version.to_s
55
- return true
56
- end
57
-
58
- def self.project_config_path
59
- files = project_config_find
60
- if files.length > 0
61
- path = files.pop
62
- else
63
- raise('No docker-sync.yml configuration found in your path ( traversing up ) Did you define it for your project?')
64
- end
65
-
66
- begin
67
- config = YAML.load_file(path)
68
- raise "Version of docker-sync.yml does not match the reqiured one" unless project_ensure_configuration_version_compatibility(config)
69
- rescue Exception => e
70
- raise "You docker-sync.yml file does either not include a version: \"#{project_required_config_version}\" setting or your setting (#{config['version']}) does not match the required version (#{project_required_config_version}). (Add this if you migrated from docker-sync 0.1.x)"
71
- end
72
- return path
73
- end
74
-
75
- # this has been ruthlessly stolen from Thor/runner.rb - please do not hunt me for that :)
76
- def self.project_config_find(skip_lookup = false)
77
- # Finds docker-sync.yml by traversing from your current directory down to the root
78
- # directory of your system. If at any time we find a docker-sync.yml file, we stop.
79
- #
80
- #
81
- # ==== Example
82
- #
83
- # If we start at /Users/wycats/dev/thor ...
84
- #
85
- # 1. /Users/wycats/dev/thor
86
- # 2. /Users/wycats/dev
87
- # 3. /Users/wycats <-- we find a docker-sync.yml here, so we stop
88
- #
89
- # Suppose we start at c:\Documents and Settings\james\dev\docker-sync ...
90
- #
91
- # 1. c:\Documents and Settings\james\dev\docker-sync.yml
92
- # 2. c:\Documents and Settings\james\dev
93
- # 3. c:\Documents and Settings\james
94
- # 4. c:\Documents and Settings
95
- # 5. c:\ <-- no docker-sync.yml found!
96
- #
97
- docker_sync_files = []
98
-
99
- unless skip_lookup
100
- Pathname.pwd.ascend do |path|
101
- docker_sync_files = globs_for_project_config(path).map { |g| Dir[g] }.flatten
102
- break unless docker_sync_files.empty?
103
- end
104
- end
105
-
106
- files = []
107
- files += docker_sync_files
108
- end
109
-
110
- # Where to look for docker-sync.yml files.
111
- #
112
- def self.globs_for_project_config(path)
113
- path = escape_globs(path)
114
- ["#{path}/docker-sync.yml"]
115
- end
116
-
117
- def self.escape_globs(path)
118
- path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
119
- end
120
- end
@@ -1,17 +0,0 @@
1
- require "yaml"
2
- require 'dotenv'
3
-
4
- module ConfigTemplate
5
- def self.interpolate_config_string(config_string)
6
- env_hash = {}
7
- ENV.each {|k,v| env_hash[k.to_sym] = v }
8
- config_string.gsub!('${', '%{')
9
- config_string = config_string % env_hash
10
- return YAML.load(config_string)
11
- end
12
- def self.interpolate_config_file(config_path)
13
- # assuming the checks that file exist have already been performed
14
- config_string = File.read(config_path)
15
- self.interpolate_config_string(config_string)
16
- end
17
- end
@@ -1,100 +0,0 @@
1
- require 'mkmf'
2
-
3
- module Preconditions
4
- def self.check_all_preconditions
5
- docker_available
6
- docker_running
7
- unison_available
8
- unox_available
9
- macfsevents_available
10
- end
11
-
12
- def self.docker_available
13
- if (find_executable0 'docker').nil?
14
- raise('Could not find docker binary in path. Please install it, e.g. using "brew install docker" or install docker-for-mac')
15
- end
16
- end
17
-
18
- def self.docker_running
19
- `docker ps`
20
- if $?.exitstatus > 0
21
- raise('No docker daemon seems to be running. Did you start your docker-for-mac / docker-machine?')
22
- end
23
- end
24
-
25
- def self.fswatch_available
26
- if (find_executable0 'fswatch').nil?
27
- raise('No fswatch available. Install it by "brew install fswatch"')
28
- end
29
- end
30
-
31
- def self.docker_sync_available
32
- if (find_executable0 'docker-sync').nil?
33
- raise('No docker-sync available. Install it by "gem install docker-sync"')
34
- end
35
- end
36
-
37
- def self.rsync_available
38
- if (find_executable0 'rsync').nil?
39
- raise('Could not find rsync binary in path. Please install it, e.g. using "brew install rsync"')
40
- end
41
- end
42
-
43
- def self.unison_available
44
- if (find_executable0 'unison').nil?
45
- raise('Could not find unison binary in path. Please install it, e.g. using "brew install unison"')
46
- end
47
- end
48
-
49
- def self.unox_available
50
- if (find_executable0 'unison-fsmonitor').nil?
51
- cmd1 = 'curl "https://raw.githubusercontent.com/hnsl/unox/master/unox.py" -o "/usr/local/bin/unison-fsmonitor" \
52
- && chmod +x /usr/local/bin/unison-fsmonitor'
53
-
54
- Thor::Shell::Basic.new.say_status 'warning', 'Could not find unison-fsmonitor (for file watching) binary in $PATH. We try to install unox now (for manual instracutions see https://github.com/hnsl/unox.)', :red
55
- if Thor::Shell::Basic.new.yes?('Shall I install unison-fsmonitor for you? (y/N)')
56
- system cmd1
57
- else
58
- raise("Please install it, see https://github.com/hnsl/unox, or simply run :\n #{cmd1}")
59
- end
60
- end
61
-
62
- end
63
-
64
- def self.macfsevents_available
65
- `python -c 'import fsevents'`
66
- unless $?.success?
67
- Thor::Shell::Basic.new.say_status 'warning','Could not find macfsevents. Will try to install it using pip', :red
68
- if find_executable0('python') == '/usr/bin/python'
69
- Thor::Shell::Basic.new.say_status 'ok','You seem to use the system python, we will need sudo below'
70
- sudo = true
71
- cmd2 = 'sudo easy_install pip && sudo pip install macfsevents'
72
- else
73
- Thor::Shell::Basic.new.say_status 'ok','You seem to have a custom python, using non-sudo commands'
74
- sudo = false
75
- cmd2 = 'easy_install pip && pip install macfsevents'
76
- end
77
- if sudo
78
- question = 'I will ask you for you root password to install macfsevent by running (This will ask for sudo, since we use the system python)'
79
- else
80
- question = 'I will now install macfsevents for you by running'
81
- end
82
-
83
- Thor::Shell::Basic.new.say_status 'info', "#{question}: `#{cmd2}\n\n"
84
- if Thor::Shell::Basic.new.yes?('Shall i continue? (y/N)')
85
- system cmd2
86
- if $?.exitstatus > 0
87
- raise('Failed to install macfsevents, please file an issue with the output of the error')
88
- end
89
- `python -c 'import fsevents'`
90
- unless $?.success?
91
- raise('Somehow could not successfully install macfsevents even though i treed. Please report this issue')
92
- end
93
- else
94
- raise('Please install macfsevents manually, see https://github.com/EugenMayer/docker-sync/wiki/1.-Installation')
95
- end
96
- end
97
-
98
-
99
- end
100
- end