dply 0.0.2

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: b85a4c3a9c6317f7eb0c58b3f6e2ba5126015fb6
4
+ data.tar.gz: 0b8fb6959886ba99125fe7559510dd54180c92a1
5
+ SHA512:
6
+ metadata.gz: dae899e3f733399352bd7ac25ba0c473e56b8fb166fba1b9478e4461393752c0dcbc8266c43ce2c6bacc6573399f53240fecd3ca8670e824f1c3fcd6068a18c8
7
+ data.tar.gz: e21cf728a5340e980e98db23705c9d36a4382dd0e431841715931cfc60c4e6176787bf70660f68a4cfb8b1297e50a273815a503de9c7de64163eb50892f24469
@@ -0,0 +1,54 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ /.config
24
+ /coverage/
25
+ /InstalledFiles
26
+ /pkg/
27
+ /spec/reports/
28
+ /test/tmp/
29
+ /test/version_tmp/
30
+ /tmp/
31
+
32
+ ## Specific to RubyMotion:
33
+ .dat*
34
+ .repl_history
35
+ build/
36
+
37
+ ## Documentation cache and generated files:
38
+ /.yardoc/
39
+ /_yardoc/
40
+ /doc/
41
+ /rdoc/
42
+
43
+ ## Environment normalisation:
44
+ /.bundle/
45
+ /lib/bundler/man/
46
+
47
+ # for a library or gem, you might want to ignore these files since the code is
48
+ # intended to run in multiple environments; otherwise, check them in:
49
+ # Gemfile.lock
50
+ # .ruby-version
51
+ # .ruby-gemset
52
+
53
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
54
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dply.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Neeraj
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # Dply
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'dply'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install dply
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/dply/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
30
+ =======
31
+ dply
32
+ ====
33
+
34
+ A rake based deploy tool
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
4
+
5
+ Signal.trap("INT") { exit 1 }
6
+
7
+ require 'optparse'
8
+ require 'dply/error'
9
+ require 'dply/version'
10
+ require 'dply/logger'
11
+ require 'dply/dplyr'
12
+ require 'pathname'
13
+
14
+ logger = ::Dply::Logger.logger
15
+ options = {}
16
+
17
+ opts_parser = OptionParser.new do |opts|
18
+
19
+ banner = []
20
+ banner << "Usage: dplyr [global options] stage command [options] args"
21
+ banner << "Commands:"
22
+ banner << " deploy"
23
+ banner << " switch"
24
+ banner << " rollback"
25
+
26
+ banner << "Options: "
27
+ opts.banner = banner.join("\n")
28
+
29
+ opts.on("-d", "--deploy-dir [DEPLOY DIR]" , "Set deploy dir") do |d|
30
+ path = Pathname.new(d)
31
+ raise ::Dply::Error, "deploy_dir path must be absolute" if path.relative?
32
+ options[:deploy_dir] = path
33
+ end
34
+
35
+ opts.on("-v", "--version", "Show version") do |v|
36
+ puts ::Dply::VERSION
37
+ exit
38
+ end
39
+
40
+ opts.on("--debug", "Show debug messages") do
41
+ options[:debug] = true
42
+ logger.level = ::Logger::DEBUG
43
+ end
44
+
45
+ opts.on("--trace", "Show debug messages and exception stack trace") do
46
+ options[:debug] = true
47
+ options[:trace] = true
48
+ logger.level = ::Logger::DEBUG
49
+ end
50
+
51
+ opts.on_tail("-h", "--help", "Show this message") do
52
+ puts opts
53
+ exit
54
+ end
55
+ end
56
+ begin
57
+ opts_parser.order!(ARGV)
58
+ deploy_dir = options[:deploy_dir] || Dir.pwd
59
+ Dir.chdir deploy_dir
60
+
61
+ stage = ARGV.shift
62
+
63
+ dplyr = ::Dply::Dplyr.new(stage, ARGV)
64
+ dplyr.run
65
+
66
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument, ::Dply::Error => e
67
+ cause = e.cause
68
+ if options[:trace]
69
+ puts cause
70
+ cause ? (raise cause) : (raise e)
71
+ else
72
+ logger.debug "#{cause.message}" if cause
73
+ logger.error "#{e.message}"
74
+ abort
75
+ end
76
+ end
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
4
+
5
+ Signal.trap("INT") { exit 1 }
6
+
7
+ require 'optparse'
8
+ require 'dply/error'
9
+ require 'dply/version'
10
+ require 'dply/logger'
11
+ require 'pathname'
12
+
13
+ logger = ::Dply::Logger.logger
14
+ options = {}
15
+
16
+ opts_parser = OptionParser.new do |opts|
17
+
18
+ banner = []
19
+ banner << "Usage: dply [global options] command [options] args"
20
+ banner << "Commands:"
21
+ banner << " deploy"
22
+ banner << " switch"
23
+ banner << " rollback"
24
+
25
+ banner << "Options: "
26
+ opts.banner = banner.join("\n")
27
+
28
+ opts.on("-d", "--deploy-dir [DEPLOY DIR]" , "Set deploy dir") do |d|
29
+ path = Pathname.new(d)
30
+ raise ::Dply::Error, "deploy_dir path must be absolute" if path.relative?
31
+ options[:deploy_dir] = path
32
+ end
33
+
34
+ opts.on("-v", "--version", "Show version") do |v|
35
+ puts ::Dply::VERSION
36
+ exit
37
+ end
38
+
39
+ opts.on("--debug", "Show debug messages") do
40
+ options[:debug] = true
41
+ logger.level = ::Logger::DEBUG
42
+ end
43
+
44
+ opts.on("--trace", "Show debug messages and exception stack trace") do
45
+ options[:debug] = true
46
+ options[:trace] = true
47
+ logger.level = ::Logger::DEBUG
48
+ end
49
+
50
+ opts.on_tail("-h", "--help", "Show this message") do
51
+ puts opts
52
+ exit
53
+ end
54
+ end
55
+
56
+ begin
57
+ opts_parser.order!(ARGV)
58
+ deploy_dir = options[:deploy_dir] || Dir.pwd
59
+ Dir.chdir deploy_dir
60
+
61
+ command = (ARGV.shift || "").to_sym
62
+ case command
63
+ when :deploy
64
+ require 'dply/cli/deploy'
65
+ cli = Dply::Cli::Deploy.new(deploy_dir, ARGV)
66
+ cli.run
67
+ when :''
68
+ puts opts_parser
69
+ else
70
+ raise Dply::Error, "no such command #{command}"
71
+ end
72
+
73
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument, ::Dply::Error => e
74
+ cause = e.cause
75
+ if options[:trace]
76
+ puts cause
77
+ cause ? (raise cause) : (raise e)
78
+ else
79
+ logger.debug "#{cause.message}" if cause
80
+ logger.error "#{e.message}"
81
+ abort
82
+ end
83
+ end
84
+
@@ -0,0 +1,119 @@
1
+ require 'open3'
2
+ require 'pty'
3
+ module Dply
4
+ class RemoteTask
5
+
6
+ attr_reader :hosts, :parallel_jobs, :task
7
+
8
+ def initialize(hosts, task, parallel_jobs: 1)
9
+ @hosts = hosts
10
+ @parallel_jobs = parallel_jobs
11
+ @task = task
12
+ end
13
+
14
+ def run
15
+ init_run
16
+ @hosts_iterator = hosts.to_enum
17
+ spawn_jobs(@hosts_iterator, parallel_jobs)
18
+ # loop do
19
+ # break if @io_objects.empty?
20
+ # r,w = IO.select(@io_objects)
21
+ # r.each do |stream|
22
+ # eof_reached = handle_ready_stream stream
23
+ # spawn_jobs(hosts_iterator, 1) if eof_reached
24
+ # end
25
+ # end
26
+ print_summary
27
+ end
28
+
29
+ private
30
+
31
+ def init_run
32
+ @io_objects = []
33
+ @io_names = {}
34
+ @wait_threads = {}
35
+ @hosts_exhausted = false
36
+ @failed_jobs = []
37
+ @successful_jobs = []
38
+ end
39
+
40
+ def spawn_job(host_info)
41
+ user = host_info[:user]
42
+ host = host_info[:host]
43
+ deploy_dir = host_info[:deploy_dir]
44
+ run_cmd = %(ssh -tt -oBatchMode=yes -l #{user} #{host} "#{cmd} -d #{deploy_dir} #{task} 2>&1")
45
+ popen(run_cmd, host_info)
46
+ # stdin, stdout, wait_thr = Open3.popen2("ssh -tt -oBatchMode=yes -l #{user} #{host} #{cmd} -d #{deploy_dir} #{task} 2>&1")
47
+ # @io_names[stdout] = host_info[:id]
48
+ # @wait_threads[host_info] = wait_thr
49
+ # @io_objects << stdout
50
+ end
51
+
52
+ def spawn_jobs(hosts_iterator, n)
53
+ return if @hosts_exhausted
54
+ n.times do
55
+ host_info = hosts_iterator.next
56
+ spawn_job(host_info)
57
+ end
58
+ rescue StopIteration
59
+ @hosts_exhausted = true
60
+ end
61
+
62
+ def cmd
63
+ "dply"
64
+ end
65
+
66
+ def handle_ready_stream(stream)
67
+ begin
68
+ host_string = "#{@io_names[stream]}".bold.grey
69
+ puts "#{host_string} #{stream.readline}"
70
+ return false
71
+ rescue EOFError,Errno::ECONNRESET, Errno::EPIPE => e
72
+ @io_objects.delete(stream)
73
+ return true
74
+ end
75
+ end
76
+
77
+ def print_summary
78
+ puts "end"
79
+ total_jobs = @wait_threads.count
80
+ successful = 0
81
+ @wait_threads.each do |host_info, thr|
82
+ status = thr.value
83
+ exit_status = status.exitstatus
84
+ if exit_status == 0
85
+ puts "success #{host_info}"
86
+ else
87
+ puts "failed #{host_info}"
88
+ end
89
+ end
90
+ end
91
+
92
+ def popen(cmd, host_info)
93
+ Thread.abort_on_exception = true
94
+ t = Thread.new do
95
+ begin
96
+ puts "here"
97
+ r, w, pid = PTY.spawn(cmd)
98
+ host_string = "#{host_info[:id]}".bold.grey
99
+ print_pty_output r, host_string
100
+ pid, status = Process.waitpid2(pid)
101
+ spawn_jobs(@hosts_iterator, 1)
102
+ status
103
+ rescue PTY::ChildExited => e
104
+ puts "in errr"
105
+ return e.status
106
+ end
107
+ end
108
+ t.abort_on_exception = true
109
+ @wait_threads[host_info] = t
110
+ t.run
111
+ end
112
+
113
+ def print_pty_output(r, host_string)
114
+ r.each { |line| puts "#{host_string} #{line}" }
115
+ rescue Errno::EIO
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,146 @@
1
+ require 'pty'
2
+ module Dply
3
+ class RemoteTask
4
+
5
+ attr_reader :hosts, :parallel_jobs, :task
6
+
7
+ def initialize(hosts, task, parallel_jobs: 1)
8
+ @hosts = hosts
9
+ @parallel_jobs = parallel_jobs
10
+ @task = task
11
+ end
12
+
13
+ def run
14
+ if parallel_jobs > 1
15
+ run_in_parallel
16
+ else
17
+ run_serially
18
+ end
19
+ end
20
+
21
+ def run_in_parallel
22
+ init_run
23
+ hosts_iterator = hosts.to_enum
24
+ spawn_jobs(hosts_iterator, parallel_jobs)
25
+ loop do
26
+ break if @io_objects.empty?
27
+ r,w = IO.select(@io_objects)
28
+ r.each do |stream|
29
+ eof_reached = handle_ready_stream stream
30
+ spawn_jobs(hosts_iterator, 1) if eof_reached
31
+ end
32
+ end
33
+ print_summary
34
+ end
35
+
36
+ def run_serially
37
+ hosts.each do |host_info|
38
+ puts "=== Running on #{host_info[:id]} ==="
39
+ run_cmd = remote_cmd host_info
40
+ system run_cmd
41
+ puts "=== end ==="
42
+ puts
43
+ raise ::Dply::Error, "remote deploy failed on #{host_info[:id]}" if $? != 0
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def init_run
50
+ @io_objects = []
51
+ @io_names = {}
52
+ @exit_statuses = {}
53
+ @hosts_exhausted = false
54
+ job_output_template
55
+ end
56
+
57
+ def spawn_job(host_info)
58
+ run_cmd = remote_cmd host_info
59
+ popen(run_cmd, host_info)
60
+ end
61
+
62
+ def spawn_jobs(hosts_iterator, n)
63
+ return if @hosts_exhausted
64
+ n.times do
65
+ host_info = hosts_iterator.next
66
+ spawn_job(host_info)
67
+ end
68
+ rescue StopIteration
69
+ @hosts_exhausted = true
70
+ end
71
+
72
+ def remote_cmd(host_info)
73
+ user = host_info[:user]
74
+ host = host_info[:host]
75
+ deploy_dir = host_info[:deploy_dir]
76
+ %(ssh -tt -oBatchMode=yes -l #{user} #{host} "dply -d #{deploy_dir} #{task} 2>&1")
77
+ end
78
+
79
+ def handle_ready_stream(stream)
80
+ host_string = "#{@io_names[stream]}"
81
+ printf @job_output_template, host_string, stream.readline
82
+ return false
83
+ rescue EOFError,Errno::ECONNRESET, Errno::EPIPE, Errno::EIO => e
84
+ @io_objects.delete(stream)
85
+ return true
86
+ end
87
+
88
+ def print_summary
89
+ total_jobs = hosts.count
90
+ run_count = @exit_statuses.count
91
+ not_run = total_jobs - run_count
92
+ failed = @exit_statuses.values.select { |v| v !=0 }.count
93
+ successful = @exit_statuses.values.select { |v| v == 0 }.count
94
+ puts "--------"
95
+ puts "Summary"
96
+ puts "--------"
97
+ puts "Succeeded: "
98
+
99
+ total_jobs = @exit_statuses.count
100
+ failed = 0
101
+ @exit_statuses.each do |host_info, status|
102
+ exit_status = status.exitstatus
103
+ if exit_status == 0
104
+ puts "#{"success".green} #{host_info[:id]} "
105
+ else
106
+ puts "#{"failed ".red} #{host_info[:id]}"
107
+ failed +=1
108
+ end
109
+ end
110
+ if failed > 0
111
+ puts "-------"
112
+ raise ::Dply::Error, "#{failed}/#{total_jobs} jobs failed" if failed > 0
113
+ end
114
+ end
115
+
116
+ def popen(cmd, host_info)
117
+ r, w, pid = PTY.spawn(cmd)
118
+ @io_objects << r
119
+ @io_names[r] = host_info[:id]
120
+ wait_thread host_info, pid
121
+ rescue PTY::ChildExited => e
122
+ @exit_statuses[host_info] = e.status
123
+ end
124
+
125
+ def wait_thread(host_info, pid)
126
+ t = Thread.new do
127
+ pid, status = Process.waitpid2(pid)
128
+ @exit_statuses[host_info] = status
129
+ end
130
+ t.abort_on_exception = true
131
+ t.run
132
+ end
133
+
134
+ def host_id_max_width
135
+ hosts.map {|h| h[:id].size }.max
136
+ end
137
+
138
+ def job_output_template
139
+ @job_output_template ||= begin
140
+ id_template = "%-#{host_id_max_width}s".bold.grey
141
+ template = "#{id_template} %s"
142
+ end
143
+ end
144
+
145
+ end
146
+ end