engineyard-serverside 1.5.28.pre.timestamps4 → 1.5.28

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ module EY
9
9
  keep_existing_assets
10
10
  cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake assets:precompile || true"
11
11
  if rails_version
12
- shell.status "Precompiling assets for rails v#{rails_version}"
12
+ info "~> Precompiling assets for rails v#{rails_version}"
13
13
  else
14
14
  warning "Precompiling assets even though Rails was not bundled."
15
15
  end
@@ -22,24 +22,24 @@ module EY
22
22
  return unless File.readable?(app_rb_path) # Not a Rails app in the first place.
23
23
 
24
24
  if File.directory?(File.join(c.release_path, 'app', 'assets'))
25
- shell.status "app/assets/ found. Attempting Rails asset pre-compilation."
25
+ info "~> app/assets/ found. Attempting Rails asset pre-compilation."
26
26
  else
27
27
  return false
28
28
  end
29
29
 
30
30
  if app_builds_own_assets?
31
- shell.status "public/assets already exists, skipping pre-compilation."
31
+ info "~> public/assets already exists, skipping pre-compilation."
32
32
  return
33
33
  end
34
34
  if app_disables_assets?(app_rb_path)
35
- shell.status "application.rb has disabled asset compilation. Skipping."
35
+ info "~> application.rb has disabled asset compilation. Skipping."
36
36
  return
37
37
  end
38
38
  # This check is very expensive, and has been deemed not worth the time.
39
39
  # Leaving this here in case someone comes up with a faster way.
40
40
  =begin
41
41
  unless app_has_asset_task?
42
- shell.status "No 'assets:precompile' Rake task found. Skipping."
42
+ info "~> No 'assets:precompile' Rake task found. Skipping."
43
43
  return
44
44
  end
45
45
  =end
@@ -1,8 +1,11 @@
1
1
  require 'open-uri'
2
+ require 'engineyard-serverside/logged_output'
2
3
 
3
4
  module EY
4
5
  module Serverside
5
6
  class Server < Struct.new(:hostname, :roles, :name, :user)
7
+ include LoggedOutput
8
+
6
9
  class DuplicateHostname < StandardError
7
10
  def initialize(hostname)
8
11
  super "There is already an EY::Serverside::Server with hostname '#{hostname}'"
@@ -70,22 +73,22 @@ module EY
70
73
  hostname == 'localhost'
71
74
  end
72
75
 
73
- def sync_directory(directory, &block)
76
+ def sync_directory(directory)
74
77
  return if local?
75
- yield remote_command("mkdir -p #{directory}")
76
- yield Escap.shell_command(%w[rsync --delete -aq -e] + [ssh_command, "#{directory}/", "#{user}@#{hostname}:#{directory}"])
78
+ run "mkdir -p #{directory}"
79
+ logged_system(%|rsync --delete -aq -e "#{ssh_command}" #{directory}/ #{user}@#{hostname}:#{directory}|)
77
80
  end
78
81
 
79
82
  def run(command)
80
- yield local? ? command : remote_command(command)
81
- end
82
-
83
- def remote_command(command)
84
- ssh_command + Escape.shell_command(["#{user}@#{hostname}", command])
83
+ if local?
84
+ logged_system(command)
85
+ else
86
+ logged_system(ssh_command + " " + Escape.shell_command(["#{user}@#{hostname}", command]))
87
+ end
85
88
  end
86
89
 
87
90
  def ssh_command
88
- "ssh -i #{ENV['HOME']}/.ssh/internal -o StrictHostKeyChecking=no -o PasswordAuthentication=no "
91
+ "ssh -i #{ENV['HOME']}/.ssh/internal -o StrictHostKeyChecking=no -o PasswordAuthentication=no"
89
92
  end
90
93
 
91
94
  end
@@ -1,3 +1,5 @@
1
+ require 'engineyard-serverside/logged_output'
2
+
1
3
  module EY
2
4
  module Serverside
3
5
  module Strategies
@@ -26,7 +28,7 @@ module EY
26
28
  #
27
29
  # Rollback doesn't know about the repository location (nor
28
30
  # should it need to), but it would like to use #short_log_message.
29
- klass.new(shell,
31
+ klass.new(
30
32
  :repository_cache => c[:repository_cache],
31
33
  :app => c[:app],
32
34
  :repo => c[:repo],
@@ -35,10 +37,11 @@ module EY
35
37
  end
36
38
  end
37
39
 
38
- attr_reader :shell, :opts
40
+ include LoggedOutput
41
+
42
+ attr_reader :opts
39
43
 
40
- def initialize(shell, opts)
41
- @shell = shell
44
+ def initialize(opts)
42
45
  @opts = opts
43
46
  end
44
47
 
@@ -48,21 +51,21 @@ module EY
48
51
 
49
52
  def fetch
50
53
  if usable_repository?
51
- shell.logged_system("#{git} fetch -q origin 2>&1")
54
+ logged_system("#{git} fetch -q origin 2>&1")
52
55
  else
53
56
  FileUtils.rm_rf(opts[:repository_cache])
54
- shell.logged_system("git clone -q #{opts[:repo]} #{opts[:repository_cache]} 2>&1")
57
+ logged_system("git clone -q #{opts[:repo]} #{opts[:repository_cache]} 2>&1")
55
58
  end
56
59
  end
57
60
 
58
61
  def checkout
59
- shell.status "Deploying revision #{short_log_message(to_checkout)}"
62
+ info "~> Deploying revision #{short_log_message(to_checkout)}"
60
63
  in_git_work_tree do
61
- (shell.logged_system("git checkout -q '#{to_checkout}'") ||
62
- shell.logged_system("git reset -q --hard '#{to_checkout}'")) &&
63
- shell.logged_system("git submodule sync") &&
64
- shell.logged_system("git submodule update --init") &&
65
- shell.logged_system("git clean -dfq")
64
+ (logged_system("git checkout -q '#{to_checkout}'") ||
65
+ logged_system("git reset -q --hard '#{to_checkout}'")) &&
66
+ logged_system("git submodule sync") &&
67
+ logged_system("git submodule update --init") &&
68
+ logged_system("git clean -dfq")
66
69
  end
67
70
  end
68
71
 
@@ -1,16 +1,12 @@
1
- require 'engineyard-serverside/shell'
2
-
3
1
  module EY
4
2
  module Serverside
5
3
  class Task
6
- include EY::Serverside::Shell::Helpers
7
4
 
8
- attr_reader :config, :shell
5
+ attr_reader :config
9
6
  alias :c :config
10
7
 
11
- def initialize(conf, shell = nil)
8
+ def initialize(conf)
12
9
  @config = conf
13
- @shell = shell
14
10
  @roles = :all
15
11
  end
16
12
 
@@ -22,7 +18,7 @@ module EY
22
18
  end
23
19
 
24
20
  if deploy_file
25
- shell.status "Loading deployment task overrides from #{deploy_file}"
21
+ puts "~> Loading deployment task overrides from #{deploy_file}"
26
22
  instance_eval(File.read(deploy_file))
27
23
  true
28
24
  else
@@ -58,7 +54,7 @@ module EY
58
54
  servers = EY::Serverside::Server.from_roles(@roles)
59
55
  futures = EY::Serverside::Future.call(servers, block_given?) do |server, exec_block|
60
56
  to_run = exec_block ? block.call(server, cmd.dup) : cmd
61
- server.run(Escape.shell_command(wrapper + [to_run])) { |cmd| shell.logged_system(cmd) }
57
+ server.run(Escape.shell_command(wrapper + [to_run]))
62
58
  end
63
59
 
64
60
  unless EY::Serverside::Future.success?(futures)
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '1.5.28.pre.timestamps4'
3
+ VERSION = '1.5.28'
4
4
  end
5
5
  end
@@ -4,23 +4,65 @@ require 'timeout'
4
4
  require 'thread'
5
5
 
6
6
  module Open4
7
- #--{{{
8
- VERSION = '1.1.0'
7
+ VERSION = '1.3.0'
9
8
  def self.version() VERSION end
10
9
 
11
10
  class Error < ::StandardError; end
12
11
 
12
+ def pfork4(fun, &b)
13
+ Open4.do_popen(b, :block) do |ps_read, _|
14
+ ps_read.close
15
+ begin
16
+ fun.call
17
+ rescue SystemExit => e
18
+ # Make it seem to the caller that calling Kernel#exit in +fun+ kills
19
+ # the child process normally. Kernel#exit! bypasses this rescue
20
+ # block.
21
+ exit! e.status
22
+ else
23
+ exit! 0
24
+ end
25
+ end
26
+ end
27
+ module_function :pfork4
28
+
13
29
  def popen4(*cmd, &b)
14
- #--{{{
30
+ Open4.do_popen(b, :init) do |ps_read, ps_write|
31
+ ps_read.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
32
+ ps_write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
33
+ exec(*cmd)
34
+ raise 'forty-two' # Is this really needed?
35
+ end
36
+ end
37
+ alias open4 popen4
38
+ module_function :popen4
39
+ module_function :open4
40
+
41
+ def popen4ext(closefds=false, *cmd, &b)
42
+ Open4.do_popen(b, :init, closefds) do |ps_read, ps_write|
43
+ ps_read.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
44
+ ps_write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
45
+ exec(*cmd)
46
+ raise 'forty-two' # Is this really needed?
47
+ end
48
+ end
49
+ module_function :popen4ext
50
+
51
+ def self.do_popen(b = nil, exception_propagation_at = nil, closefds=false, &cmd)
15
52
  pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
16
53
 
17
54
  verbose = $VERBOSE
18
55
  begin
19
56
  $VERBOSE = nil
20
- ps.first.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
21
- ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
22
57
 
23
58
  cid = fork {
59
+ if closefds
60
+ exlist = [0, 1, 2] | [pw,pr,pe,ps].map{|p| [p.first.fileno, p.last.fileno] }.flatten
61
+ ObjectSpace.each_object(IO){|io|
62
+ io.close if (not io.closed?) and (not exlist.include? io.fileno)
63
+ }
64
+ end
65
+
24
66
  pw.last.close
25
67
  STDIN.reopen pw.first
26
68
  pw.first.close
@@ -36,52 +78,59 @@ module Open4
36
78
  STDOUT.sync = STDERR.sync = true
37
79
 
38
80
  begin
39
- exec(*cmd)
40
- raise 'forty-two'
81
+ cmd.call(ps)
41
82
  rescue Exception => e
42
83
  Marshal.dump(e, ps.last)
43
84
  ps.last.flush
85
+ ensure
86
+ ps.last.close unless ps.last.closed?
44
87
  end
45
- ps.last.close unless (ps.last.closed?)
88
+
46
89
  exit!
47
90
  }
48
91
  ensure
49
92
  $VERBOSE = verbose
50
93
  end
51
94
 
52
- [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
95
+ [ pw.first, pr.last, pe.last, ps.last ].each { |fd| fd.close }
53
96
 
54
- begin
55
- e = Marshal.load ps.first
56
- raise(Exception === e ? e : "unknown failure!")
57
- rescue EOFError # If we get an EOF error, then the exec was successful
58
- 42
59
- ensure
60
- ps.first.close
61
- end
97
+ Open4.propagate_exception cid, ps.first if exception_propagation_at == :init
62
98
 
63
99
  pw.last.sync = true
64
100
 
65
- pi = [pw.last, pr.first, pe.first]
101
+ pi = [ pw.last, pr.first, pe.first ]
102
+
103
+ begin
104
+ return [cid, *pi] unless b
66
105
 
67
- if b
68
106
  begin
69
- b[cid, *pi]
70
- Process.waitpid2(cid).last
107
+ b.call(cid, *pi)
71
108
  ensure
72
- pi.each{|fd| fd.close unless fd.closed?}
109
+ pi.each { |fd| fd.close unless fd.closed? }
73
110
  end
74
- else
75
- [cid, pw.last, pr.first, pe.first]
111
+
112
+ Open4.propagate_exception cid, ps.first if exception_propagation_at == :block
113
+
114
+ Process.waitpid2(cid).last
115
+ ensure
116
+ ps.first.close unless ps.first.closed?
76
117
  end
77
- #--}}}
78
118
  end
79
- alias open4 popen4
80
- module_function :popen4
81
- module_function :open4
119
+
120
+ def self.propagate_exception(cid, ps_read)
121
+ e = Marshal.load ps_read
122
+ raise Exception === e ? e : "unknown failure!"
123
+ rescue EOFError
124
+ # Child process did not raise exception.
125
+ rescue
126
+ # Child process raised exception; wait it in order to avoid a zombie.
127
+ Process.waitpid2 cid
128
+ raise
129
+ ensure
130
+ ps_read.close
131
+ end
82
132
 
83
133
  class SpawnError < Error
84
- #--{{{
85
134
  attr 'cmd'
86
135
  attr 'status'
87
136
  attr 'signals'
@@ -98,11 +147,9 @@ module Open4
98
147
  sigs = @signals.map{|k,v| "#{ k }:#{ v.inspect }"}.join(' ')
99
148
  super "cmd <#{ cmd }> failed with status <#{ exitstatus.inspect }> signals <#{ sigs }>"
100
149
  end
101
- #--}}}
102
150
  end
103
151
 
104
152
  class ThreadEnsemble
105
- #--{{{
106
153
  attr 'threads'
107
154
 
108
155
  def initialize cid
@@ -154,18 +201,14 @@ module Open4
154
201
  def all_done
155
202
  @threads.size.times{ @done.pop }
156
203
  end
157
- #--}}}
158
204
  end
159
205
 
160
206
  def to timeout = nil
161
- #--{{{
162
207
  Timeout.timeout(timeout){ yield }
163
- #--}}}
164
208
  end
165
209
  module_function :to
166
210
 
167
211
  def new_thread *a, &b
168
- #--{{{
169
212
  cur = Thread.current
170
213
  Thread.new(*a) do |*a|
171
214
  begin
@@ -174,29 +217,25 @@ module Open4
174
217
  cur.raise e
175
218
  end
176
219
  end
177
- #--}}}
178
220
  end
179
221
  module_function :new_thread
180
222
 
181
223
  def getopts opts = {}
182
- #--{{{
183
224
  lambda do |*args|
184
225
  keys, default, ignored = args
185
- catch('opt') do
226
+ catch(:opt) do
186
227
  [keys].flatten.each do |key|
187
228
  [key, key.to_s, key.to_s.intern].each do |key|
188
- throw 'opt', opts[key] if opts.has_key?(key)
229
+ throw :opt, opts[key] if opts.has_key?(key)
189
230
  end
190
231
  end
191
232
  default
192
233
  end
193
234
  end
194
- #--}}}
195
235
  end
196
236
  module_function :getopts
197
237
 
198
238
  def relay src, dst = nil, t = nil
199
- #--{{{
200
239
  send_dst =
201
240
  if dst.respond_to?(:call)
202
241
  lambda{|buf| dst.call(buf)}
@@ -244,12 +283,10 @@ module Open4
244
283
  send_dst[buf]
245
284
  end
246
285
  end
247
- #--}}}
248
286
  end
249
287
  module_function :relay
250
288
 
251
289
  def spawn arg, *argv
252
- #--{{{
253
290
  argv.unshift(arg)
254
291
  opts = ((argv.size > 1 and Hash === argv.last) ? argv.pop : {})
255
292
  argv.flatten!
@@ -325,7 +362,6 @@ module Open4
325
362
  (ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus))
326
363
 
327
364
  status
328
- #--}}}
329
365
  end
330
366
  module_function :spawn
331
367
 
@@ -336,7 +372,6 @@ module Open4
336
372
  module_function :chdir
337
373
 
338
374
  def background arg, *argv
339
- #--{{{
340
375
  require 'thread'
341
376
  q = Queue.new
342
377
  opts = { 'pid' => q, :pid => q }
@@ -354,14 +389,12 @@ module Open4
354
389
  define_method(:exitstatus){ @exitstatus ||= spawn_status.exitstatus }
355
390
  }
356
391
  thread
357
- #--}}}
358
392
  end
359
393
  alias bg background
360
394
  module_function :background
361
395
  module_function :bg
362
396
 
363
397
  def maim pid, opts = {}
364
- #--{{{
365
398
  getopt = getopts opts
366
399
  sigs = getopt[ 'signals', %w(SIGTERM SIGQUIT SIGKILL) ]
367
400
  suspend = getopt[ 'suspend', 4 ]
@@ -379,12 +412,10 @@ module Open4
379
412
  return true unless alive? pid
380
413
  end
381
414
  return(not alive?(pid))
382
- #--}}}
383
415
  end
384
416
  module_function :maim
385
417
 
386
418
  def alive pid
387
- #--{{{
388
419
  pid = Integer pid
389
420
  begin
390
421
  Process.kill 0, pid
@@ -392,12 +423,10 @@ module Open4
392
423
  rescue Errno::ESRCH
393
424
  false
394
425
  end
395
- #--}}}
396
426
  end
397
427
  alias alive? alive
398
428
  module_function :alive
399
429
  module_function :'alive?'
400
- #--}}}
401
430
  end
402
431
 
403
432
  def open4(*cmd, &b) cmd.size == 0 ? Open4 : Open4::popen4(*cmd, &b) end