docker-sync 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6f672a525e3ac21a5fe659eb7d0a15d8ba617e14
4
+ data.tar.gz: cbacd747e7959c1319c1f897070bd1d6d3a7da18
5
+ SHA512:
6
+ metadata.gz: c9ac6925db1d1e9da1088d6f85c82a0a47e4183933da35873df1aa02d7b93ed868976705cd496b9b98afaf41f10f551c1b1ca7f1baa95397b87e8cfe2aeb59cb
7
+ data.tar.gz: 973e7208ff7e7f9d560ba96f3a93d40bd56f7a82f4f02207a865248cb6d9c11dbaf0785ef6ab677f2e9205198e1b96a61310ee5810a53d1730aa87b0e34e238c
@@ -0,0 +1,7 @@
1
+ #lib = File.expand_path('./lib', __dir__)
2
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
3
+
4
+ thor = File.expand_path('../tasks', __FILE__)
5
+ Dir.glob(File.join(thor, '/**/*.thor')).each { |taskfile|
6
+ load taskfile
7
+ }
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thor"
4
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
+
6
+ thor = File.expand_path('../../tasks', __FILE__)
7
+ Dir.glob(File.join(thor, '/**/*.thor')).each { |taskfile|
8
+ load taskfile
9
+ }
10
+
11
+ Sync.start
@@ -0,0 +1,59 @@
1
+ require 'pp'
2
+ require 'Pathname'
3
+ # this has basically completely reused from Thor::runner.rb - thank you!
4
+
5
+ module DockerSyncConfig
6
+ def find_config
7
+ files = find_config_file
8
+ if files.length > 0
9
+ return files.pop
10
+ else
11
+ raise('No docker-sync.yml configuration found in your path ( traversing up ) Did you define it for your project?')
12
+ end
13
+ end
14
+ # this has been ruthlessly stolen from Thor/runner.rb - please do not hunt me for that :)
15
+ def find_config_file(skip_lookup = false)
16
+ # Finds docker-sync.yml by traversing from your current directory down to the root
17
+ # directory of your system. If at any time we find a docker-sync.yml file, we stop.
18
+ #
19
+ #
20
+ # ==== Example
21
+ #
22
+ # If we start at /Users/wycats/dev/thor ...
23
+ #
24
+ # 1. /Users/wycats/dev/thor
25
+ # 2. /Users/wycats/dev
26
+ # 3. /Users/wycats <-- we find a docker-sync.yml here, so we stop
27
+ #
28
+ # Suppose we start at c:\Documents and Settings\james\dev\docker-sync ...
29
+ #
30
+ # 1. c:\Documents and Settings\james\dev\docker-sync.yml
31
+ # 2. c:\Documents and Settings\james\dev
32
+ # 3. c:\Documents and Settings\james
33
+ # 4. c:\Documents and Settings
34
+ # 5. c:\ <-- no docker-sync.yml found!
35
+ #
36
+ docker_sync_files = []
37
+
38
+ unless skip_lookup
39
+ Pathname.pwd.ascend do |path|
40
+ docker_sync_files = globs_for_config(path).map { |g| Dir[g] }.flatten
41
+ break unless docker_sync_files.empty?
42
+ end
43
+ end
44
+
45
+ files = []
46
+ files += docker_sync_files
47
+ end
48
+
49
+ # Where to look for docker-sync.yml files.
50
+ #
51
+ def globs_for_config(path)
52
+ path = escape_globs(path)
53
+ ["#{path}/docker-sync.yml"]
54
+ end
55
+
56
+ def escape_globs(path)
57
+ path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
58
+ end
59
+ end
@@ -0,0 +1,133 @@
1
+ require 'thor/shell'
2
+ require 'docker_sync/sync_process'
3
+ require 'execution'
4
+ require 'yaml'
5
+
6
+ module Docker_Rsync
7
+ class SyncManager
8
+ include Thor::Shell
9
+
10
+ @sync_processes
11
+ @configurations
12
+ @config_path
13
+ def initialize(options)
14
+ @sync_processes = []
15
+ @config_syncs = []
16
+ @config_options = []
17
+ @config_syncs = []
18
+ @config_path = options[:config_path]
19
+ load_configuration
20
+ end
21
+
22
+ def load_configuration
23
+ unless File.exist?(@config_path)
24
+ raise "Config could not be loaded from #{@config_path} - it does not exist"
25
+ end
26
+
27
+ config = YAML.load_file(@config_path)
28
+ validate_config(config)
29
+ @config_options = config['options'] || {}
30
+ @config_syncs = config['syncs']
31
+ upgrade_syncs_config
32
+ end
33
+
34
+ def get_sync_points
35
+ return @config_syncs
36
+ end
37
+
38
+ def upgrade_syncs_config
39
+ @config_syncs.each do |name, config|
40
+ @config_syncs[name]['config_path'] = @config_path
41
+ @config_syncs[name]['src'] = File.expand_path(@config_syncs[name]['src'])
42
+ unless config.key?('verbose')
43
+ @config_syncs[name]['verbose'] = @config_options['verbose'] || false
44
+ end
45
+ end
46
+ end
47
+
48
+ def validate_config(config)
49
+ unless config.key?('syncs')
50
+ raise ('no syncs defined')
51
+ end
52
+
53
+ config['syncs'].each do |name, sync_config|
54
+ validate_sync_config(name, sync_config)
55
+ end
56
+
57
+ return true
58
+ end
59
+
60
+ def validate_sync_config(name, sync_config)
61
+ %w[src dest sync_host_port].each do |key|
62
+ raise ("#{name} does not have #{key} condiguration value set - this is mandatory") unless sync_config.key?(key)
63
+ end
64
+ end
65
+
66
+ def init_sync_processes(sync_name = nil)
67
+ if sync_name.nil?
68
+ @config_syncs.each { |name,sync_configuration|
69
+ @sync_processes.push(create_sync(name, sync_configuration))
70
+ }
71
+ else
72
+ unless @config_syncs.key?(sync_name)
73
+ raise("Could not find sync configuration with name #{sync_name}")
74
+ end
75
+ @sync_processes.push(create_sync(sync_name, @config_syncs[sync_name]))
76
+ end
77
+ end
78
+
79
+
80
+ def clean(sync_name = nil)
81
+ init_sync_processes(sync_name)
82
+ @sync_processes.each { |sync_process|
83
+ sync_process.clean
84
+ }
85
+ end
86
+
87
+ def sync(sync_name = nil)
88
+ init_sync_processes(sync_name)
89
+ @sync_processes.each { |sync_process|
90
+ sync_process.sync
91
+ }
92
+ end
93
+
94
+ def run(sync_name = nil)
95
+ init_sync_processes(sync_name)
96
+
97
+ @sync_processes.each { |sync_process|
98
+ sync_process.run
99
+ }
100
+
101
+ begin
102
+ @sync_processes.each do |sync_process|
103
+ sync_process.watch_thread.join
104
+ end
105
+
106
+ rescue SystemExit, Interrupt
107
+
108
+ puts "Shutting down..."
109
+ @sync_processes.each do |sync_process|
110
+ sync_process.stop
111
+ end
112
+ @sync_processes.each do |sync_process|
113
+ sync_process.watch_thread.kill
114
+ end
115
+
116
+ rescue Exception => e
117
+
118
+ puts "EXCEPTION: #{e.inspect}"
119
+ puts "MESSAGE: #{e.message}"
120
+
121
+ end
122
+ end
123
+
124
+ def create_sync(sync_name, sync_configuration)
125
+ sync_process = Docker_Sync::SyncProcess.new(sync_name, sync_configuration)
126
+ return sync_process
127
+ end
128
+
129
+ def stop
130
+
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,133 @@
1
+ require 'thor/shell'
2
+ require 'execution'
3
+ require 'shellwords'
4
+ module Docker_Sync
5
+ class SyncProcess
6
+ include Thor::Shell
7
+ include Execution
8
+ @options
9
+ @sync_name
10
+ @watch_thread
11
+
12
+ def initialize(sync_name, options)
13
+ defaults = {
14
+ 'verbose' => false,
15
+ 'sync_host_ip' => get_host_ip
16
+ }
17
+ @sync_name = sync_name
18
+ @options = defaults.merge(options)
19
+
20
+ end
21
+
22
+ def get_host_ip
23
+ return 'localhost'
24
+ end
25
+
26
+ def run
27
+ start_container
28
+ sync
29
+ watch
30
+ end
31
+
32
+ def stop
33
+ say_status 'ok', "Stopping sync container #{@sync_name}"
34
+ begin
35
+ `docker stop #{@sync_name}`
36
+ rescue Exception => e
37
+ say_status 'error', "Stopping failed of #{@sync_name}:", :red
38
+ puts e.message
39
+ end
40
+ end
41
+
42
+ def start_container
43
+ say_status 'ok', 'Starting rsync', :white
44
+ running = `docker ps --filter 'status=running' --filter 'name=#{@sync_name}' | grep #{@sync_name}`
45
+ if running == ''
46
+ say_status 'ok', "#{@sync_name} container not running", :white
47
+ exists = `docker ps --filter "status=exited" --filter "name=filesync_dw" | grep filesync_dw`
48
+ if exists == ''
49
+ say_status 'ok', "creating #{@sync_name} container", :white
50
+ cmd = "docker run -p '#{@options['sync_host_port']}:873' -v #{@sync_name}:#{@options['dest']} -e VOLUME=#{@options['dest']} --name #{@sync_name} -d eugenmayer/rsync"
51
+ else
52
+ say_status 'success', "starting #{@sync_name} container", :green
53
+ cmd = "docker start #{@sync_name}"
54
+ end
55
+ say_status 'command', cmd, :white
56
+ `#{cmd}` || raise('Start failed')
57
+ else
58
+ say_status 'ok', "#{@sync_name} container still running", :blue
59
+ end
60
+ say_status 'success', "starting initial #{@sync_name} of src", :green
61
+ # this sleep is needed since the container could be not started
62
+ sleep 1
63
+ sync
64
+ end
65
+
66
+ def stop_container
67
+ `docker stop #{@sync_name}`
68
+ end
69
+
70
+ def reset_container
71
+ stop_container
72
+ `docker rm #{@sync_name}`
73
+ `docker volume rm #{@sync_name}`
74
+ end
75
+
76
+ def clean
77
+ reset_container
78
+ end
79
+
80
+ def sync
81
+ args = sync_options
82
+ cmd = 'rsync ' + args.join(' ')
83
+
84
+ say_status 'command', cmd, :white if @options['verbose']
85
+
86
+ out = `#{cmd}`
87
+ if $?.exitstatus > 0
88
+ say_status 'error', "Error starting sync, exit code #{$?.exitstatus}", :red
89
+ say_status 'message', out
90
+ else
91
+ say_status 'success', "Synced #{@options['src']}", :green
92
+ if @options['verbose']
93
+ say_status 'output', out
94
+ end
95
+ end
96
+ end
97
+
98
+ def sync_options
99
+ args = []
100
+ unless @options['sync_excludes'].nil?
101
+ args = @options['sync_excludes'].map { |pattern| "--exclude='#{pattern}'" } + args
102
+ end
103
+ args.push('-ap')
104
+ args.push(@options['sync_args']) if @options.key?('sync_args')
105
+ args.push("#{@options['src']}/") # add a trailing slash
106
+ args.push("rsync://#{@options['sync_host_ip']}:#{@options['sync_host_port']}/volume")
107
+ end
108
+
109
+ def watch
110
+ args = watch_options
111
+ say_status 'ok', "Starting to watch #{@options['src']} - Press CTRL-C to stop", :green
112
+ cmd = 'fswatch ' + args.join(' ')
113
+ say_status 'command', cmd, :white if @options['verbose']
114
+
115
+ @watch_thread = threadexec(cmd, "Sync #{@sync_name}", :blue)
116
+ end
117
+
118
+ def watch_options
119
+ args = []
120
+ unless @options['watch_excludes'].nil?
121
+ args = @options['watch_excludes'].map { |pattern| "--exclude='#{pattern}'" } + args
122
+ end
123
+ args.push('-orIE')
124
+ args.push(@options['watch_args']) if @options.key?('watch_args')
125
+ args.push(@options['src'])
126
+ args.push(" | xargs -I -n1 thor sync:sync -n #{@sync_name} --config='#{@options['config_path']}'")
127
+ end
128
+
129
+ def watch_thread
130
+ return @watch_thread
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,34 @@
1
+ require 'open3'
2
+ require 'colorize'
3
+
4
+ module Execution
5
+
6
+ Thread.abort_on_exception = true
7
+
8
+ def threadexec(command, prefix = nil, color = nil)
9
+
10
+ unless prefix.nil?
11
+ prefix = "#{prefix} | "
12
+ end
13
+
14
+ if color.nil?
15
+ color = :cyan
16
+ end
17
+
18
+ Thread.new {
19
+ Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
20
+
21
+ while lineOut = stdout.gets
22
+ puts prefix.nil? ? lineOut : prefix.colorize(color) + lineOut
23
+ end
24
+
25
+ while lineErr = stderr.gets
26
+ puts prefix.nil? ? lineErr : prefix.colorize(color) + lineErr
27
+ end
28
+
29
+ end
30
+ }
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,81 @@
1
+ require 'docker_sync/sync_manager'
2
+ require 'config'
3
+
4
+ class Sync < Thor
5
+ include DockerSyncConfig
6
+ class_option :config, :aliases => '-c',:default => nil, :type => :string, :desc => 'Path of the docker_sync config'
7
+ class_option :sync_name, :aliases => '-n',:type => :string, :desc => 'If given, only this sync configuration will be references/started/synced'
8
+
9
+ desc 'start', 'Start all sync configurations in this project'
10
+ def start
11
+ if options[:config]
12
+ config_path = options[:config]
13
+ else
14
+ begin
15
+ config_path = find_config
16
+ rescue Exception => e
17
+ say_status 'error', e.message, :red
18
+ return
19
+ end
20
+ end
21
+ @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
22
+ @sync_manager.run(options[:sync_name])
23
+ end
24
+
25
+ desc 'sync_only', 'sync - do not start a watcher'
26
+ def sync
27
+ if options[:config]
28
+ config_path = options[:config]
29
+ else
30
+ begin
31
+ config_path = find_config
32
+ rescue Exception => e
33
+ say_status 'error', e.message, :red
34
+ return
35
+ end
36
+ end
37
+ @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
38
+ @sync_manager.sync(options[:sync_name])
39
+ end
40
+
41
+ desc 'clean', 'Stop and clean up all sync endpoints'
42
+ def clean
43
+ if options[:config]
44
+ config_path = options[:config]
45
+ else
46
+ begin
47
+ config_path = find_config
48
+ rescue Exception => e
49
+ say_status 'error', e.message, :red
50
+ return
51
+ end
52
+ end
53
+ @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
54
+ @sync_manager.clean(options[:sync_name])
55
+ say_status 'success', 'Finished cleanup. Removed stopped, removed sync container and removed there volumes', :green
56
+ end
57
+
58
+ desc 'list', 'List all sync-points of the project configuration path'
59
+ method_option :verbose, :default => false, :type => :boolean, :desc => 'Verbose output'
60
+ def list
61
+ if options[:config]
62
+ config_path = options[:config]
63
+ else
64
+ begin
65
+ config_path = find_config
66
+ rescue Exception => e
67
+ say_status 'error', e.message, :red
68
+ return
69
+ end
70
+ end
71
+
72
+ say_status 'ok',"Found configuration at #{config_path}"
73
+ @sync_manager = Docker_Rsync::SyncManager.new(:config_path => config_path)
74
+ @sync_manager.get_sync_points.each do |name, config|
75
+ say_status name, "On address #{config['sync_host_ip']}:#{config['sync_host_port']}",:white unless options['verbose']
76
+ puts "\n---------------[#{name}] #{config['sync_host_ip']}:#{config['sync_host_port']} ---------------\n" if options['verbose']
77
+ print_table(config) if options['verbose']
78
+ end
79
+ end
80
+
81
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docker-sync
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Eugen Mayer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Sync your code live to docker-containers without losing any performance
42
+ on OSX
43
+ email: eugen.mayer@kontextwork.de
44
+ executables:
45
+ - docker-sync
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - Thorfile
50
+ - bin/docker-sync
51
+ - lib/config.rb
52
+ - lib/docker_sync/sync_manager.rb
53
+ - lib/docker_sync/sync_process.rb
54
+ - lib/execution.rb
55
+ - tasks/sync.thor
56
+ homepage: https://github.com/EugenMayer/docker_sync
57
+ licenses:
58
+ - GPL
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.4.5.1
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Docker Sync - Fast and efficient way to sync code to docker-containers
80
+ test_files: []