docker-sync 0.0.4

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.
@@ -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: []