engineyard-serverside 1.6.0.pre5 → 1.6.3

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.
Files changed (34) hide show
  1. data/lib/engineyard-serverside.rb +1 -3
  2. data/lib/engineyard-serverside/cli.rb +38 -73
  3. data/lib/engineyard-serverside/configuration.rb +12 -38
  4. data/lib/engineyard-serverside/deploy.rb +54 -63
  5. data/lib/engineyard-serverside/deploy_hook.rb +18 -21
  6. data/lib/engineyard-serverside/deprecation.rb +17 -9
  7. data/lib/engineyard-serverside/lockfile_parser.rb +1 -1
  8. data/lib/engineyard-serverside/logged_output.rb +91 -0
  9. data/lib/engineyard-serverside/rails_asset_support.rb +5 -5
  10. data/lib/engineyard-serverside/server.rb +11 -8
  11. data/lib/engineyard-serverside/strategies/git.rb +15 -12
  12. data/lib/engineyard-serverside/task.rb +8 -29
  13. data/lib/engineyard-serverside/version.rb +1 -1
  14. data/lib/vendor/systemu/LICENSE +3 -0
  15. data/lib/vendor/systemu/lib/systemu.rb +363 -0
  16. data/lib/vendor/systemu/systemu.gemspec +45 -0
  17. data/spec/basic_deploy_spec.rb +9 -9
  18. data/spec/bundler_deploy_spec.rb +1 -1
  19. data/spec/custom_deploy_spec.rb +4 -63
  20. data/spec/deploy_hook_spec.rb +78 -77
  21. data/spec/deprecation_spec.rb +26 -4
  22. data/spec/git_strategy_spec.rb +2 -6
  23. data/spec/logged_output_spec.rb +55 -0
  24. data/spec/nodejs_deploy_spec.rb +2 -2
  25. data/spec/services_deploy_spec.rb +10 -11
  26. data/spec/spec_helper.rb +25 -48
  27. data/spec/sqlite3_deploy_spec.rb +2 -1
  28. data/spec/support/integration.rb +14 -2
  29. metadata +79 -94
  30. data/lib/engineyard-serverside/shell.rb +0 -102
  31. data/lib/engineyard-serverside/shell/formatter.rb +0 -73
  32. data/lib/engineyard-serverside/shell/helpers.rb +0 -29
  33. data/lib/vendor/open4/lib/open4.rb +0 -432
  34. data/spec/shell_spec.rb +0 -50
@@ -0,0 +1,363 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tmpdir'
4
+ require 'socket'
5
+ require 'fileutils'
6
+ require 'rbconfig'
7
+ require 'thread'
8
+
9
+ class Object
10
+ def systemu(*a, &b) SystemUniversal.new(*a, &b).systemu end
11
+ end
12
+
13
+ class SystemUniversal
14
+ #
15
+ # constants
16
+ #
17
+ SystemUniversal::VERSION = '2.5.0' unless SystemUniversal.send(:const_defined?, :VERSION)
18
+ def SystemUniversal.version() SystemUniversal::VERSION end
19
+ def version() SystemUniversal::VERSION end
20
+ #
21
+ # class methods
22
+ #
23
+
24
+ @host = Socket.gethostname
25
+ @ppid = Process.ppid
26
+ @pid = Process.pid
27
+ @turd = ENV['SYSTEMU_TURD']
28
+
29
+ c = begin; ::RbConfig::CONFIG; rescue NameError; ::Config::CONFIG; end
30
+ ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
31
+ @ruby = if system('%s -e 42' % ruby)
32
+ ruby
33
+ else
34
+ system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG')
35
+ end
36
+
37
+ class << SystemUniversal
38
+ %w( host ppid pid ruby turd ).each{|a| attr_accessor a}
39
+
40
+ def quote(*words)
41
+ words.map{|word| word.inspect}.join(' ')
42
+ end
43
+ end
44
+
45
+ #
46
+ # instance methods
47
+ #
48
+
49
+ def initialize argv, opts = {}, &block
50
+ getopt = getopts opts
51
+
52
+ @argv = argv
53
+ @block = block
54
+
55
+ @stdin = getopt[ ['stdin', 'in', '0', 0] ]
56
+ @stdout = getopt[ ['stdout', 'out', '1', 1] ]
57
+ @stderr = getopt[ ['stderr', 'err', '2', 2] ]
58
+ @env = getopt[ 'env' ]
59
+ @cwd = getopt[ 'cwd' ]
60
+
61
+ @host = getopt[ 'host', self.class.host ]
62
+ @ppid = getopt[ 'ppid', self.class.ppid ]
63
+ @pid = getopt[ 'pid', self.class.pid ]
64
+ @ruby = getopt[ 'ruby', self.class.ruby ]
65
+ end
66
+
67
+ def systemu
68
+ tmpdir do |tmp|
69
+ c = child_setup tmp
70
+ status = nil
71
+
72
+ begin
73
+ thread = nil
74
+
75
+ quietly{
76
+ IO.popen "#{ quote(@ruby) } #{ quote(c['program']) }", 'r+' do |pipe|
77
+ line = pipe.gets
78
+ case line
79
+ when %r/^pid: \d+$/
80
+ cid = Integer line[%r/\d+/]
81
+ else
82
+ begin
83
+ buf = pipe.read
84
+ buf = "#{ line }#{ buf }"
85
+ e = Marshal.load buf
86
+ raise unless Exception === e
87
+ raise e
88
+ rescue
89
+ raise "wtf?\n#{ buf }\n"
90
+ end
91
+ end
92
+ thread = new_thread cid, @block if @block
93
+ pipe.read rescue nil
94
+ end
95
+ }
96
+ status = $?
97
+ ensure
98
+ if thread
99
+ begin
100
+ class << status
101
+ attr 'thread'
102
+ end
103
+ status.instance_eval{ @thread = thread }
104
+ rescue
105
+ 42
106
+ end
107
+ end
108
+ end
109
+
110
+ if @stdout or @stderr
111
+ open(c['stdout']){|f| relay f => @stdout} if @stdout
112
+ open(c['stderr']){|f| relay f => @stderr} if @stderr
113
+ status
114
+ else
115
+ [status, IO.read(c['stdout']), IO.read(c['stderr'])]
116
+ end
117
+ end
118
+ end
119
+
120
+ def quote *args, &block
121
+ SystemUniversal.quote(*args, &block)
122
+ end
123
+
124
+ def new_thread cid, block
125
+ q = Queue.new
126
+ Thread.new(cid) do |cid|
127
+ current = Thread.current
128
+ current.abort_on_exception = true
129
+ q.push current
130
+ block.call cid
131
+ end
132
+ q.pop
133
+ end
134
+
135
+ def child_setup tmp
136
+ stdin = File.expand_path(File.join(tmp, 'stdin'))
137
+ stdout = File.expand_path(File.join(tmp, 'stdout'))
138
+ stderr = File.expand_path(File.join(tmp, 'stderr'))
139
+ program = File.expand_path(File.join(tmp, 'program'))
140
+ config = File.expand_path(File.join(tmp, 'config'))
141
+
142
+ if @stdin
143
+ open(stdin, 'w'){|f| relay @stdin => f}
144
+ else
145
+ FileUtils.touch stdin
146
+ end
147
+ FileUtils.touch stdout
148
+ FileUtils.touch stderr
149
+
150
+ c = {}
151
+ c['argv'] = @argv
152
+ c['env'] = @env
153
+ c['cwd'] = @cwd
154
+ c['stdin'] = stdin
155
+ c['stdout'] = stdout
156
+ c['stderr'] = stderr
157
+ c['program'] = program
158
+ open(config, 'w'){|f| Marshal.dump(c, f)}
159
+
160
+ open(program, 'w'){|f| f.write child_program(config)}
161
+
162
+ c
163
+ end
164
+
165
+ def quietly
166
+ v = $VERBOSE
167
+ $VERBOSE = nil
168
+ yield
169
+ ensure
170
+ $VERBOSE = v
171
+ end
172
+
173
+ def child_program config
174
+ <<-program
175
+ # encoding: utf-8
176
+
177
+ PIPE = STDOUT.dup
178
+ begin
179
+ config = Marshal.load(IO.read('#{ config }'))
180
+
181
+ argv = config['argv']
182
+ env = config['env']
183
+ cwd = config['cwd']
184
+ stdin = config['stdin']
185
+ stdout = config['stdout']
186
+ stderr = config['stderr']
187
+
188
+ Dir.chdir cwd if cwd
189
+ env.each{|k,v| ENV[k.to_s] = v.to_s} if env
190
+
191
+ STDIN.reopen stdin
192
+ STDOUT.reopen stdout
193
+ STDERR.reopen stderr
194
+
195
+ PIPE.puts "pid: \#{ Process.pid }"
196
+ PIPE.flush ### the process is ready yo!
197
+ PIPE.close
198
+ if RUBY_VERSION >= "1.9"
199
+ exec *argv
200
+ else
201
+ exec argv
202
+ end
203
+ rescue Exception => e
204
+ PIPE.write Marshal.dump(e) rescue nil
205
+ exit 42
206
+ end
207
+ program
208
+ end
209
+
210
+ def relay srcdst
211
+ src, dst, ignored = srcdst.to_a.first
212
+ if src.respond_to? 'read'
213
+ while((buf = src.read(8192))); dst << buf; end
214
+ else
215
+ if src.respond_to?(:each_line)
216
+ src.each_line{|buf| dst << buf}
217
+ else
218
+ src.each{|buf| dst << buf}
219
+ end
220
+ end
221
+ end
222
+
223
+ def tmpdir d = Dir.tmpdir, max = 42, &b
224
+ i = -1 and loop{
225
+ i += 1
226
+
227
+ tmp = File.join d, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
228
+
229
+ begin
230
+ Dir.mkdir tmp
231
+ rescue Errno::EEXIST
232
+ raise if i >= max
233
+ next
234
+ end
235
+
236
+ break(
237
+ if b
238
+ begin
239
+ b.call tmp
240
+ ensure
241
+ FileUtils.rm_rf tmp unless SystemU.turd
242
+ end
243
+ else
244
+ tmp
245
+ end
246
+ )
247
+ }
248
+ end
249
+
250
+ def getopts opts = {}
251
+ lambda do |*args|
252
+ keys, default, ignored = args
253
+ catch(:opt) do
254
+ [keys].flatten.each do |key|
255
+ [key, key.to_s, key.to_s.intern].each do |key|
256
+ throw :opt, opts[key] if opts.has_key?(key)
257
+ end
258
+ end
259
+ default
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ # some monkeypatching for JRuby
266
+ if defined? JRUBY_VERSION
267
+ require 'jruby'
268
+ java_import org.jruby.RubyProcess
269
+
270
+ class SystemUniversal
271
+ def systemu
272
+ split_argv = JRuby::PathHelper.smart_split_command @argv
273
+ process = java.lang.Runtime.runtime.exec split_argv.to_java(:string)
274
+
275
+ stdout, stderr = [process.input_stream, process.error_stream].map do |stream|
276
+ StreamReader.new(stream)
277
+ end
278
+
279
+ exit_code = process.wait_for
280
+ field = process.get_class.get_declared_field("pid")
281
+ field.set_accessible(true)
282
+ pid = field.get(process)
283
+ [
284
+ RubyProcess::RubyStatus.new_process_status(JRuby.runtime, exit_code, pid),
285
+ stdout.join,
286
+ stderr.join
287
+ ]
288
+ end
289
+
290
+ class StreamReader
291
+ def initialize(stream)
292
+ @data = ""
293
+ @thread = Thread.new do
294
+ reader = java.io.BufferedReader.new java.io.InputStreamReader.new(stream)
295
+
296
+ while line = reader.read_line
297
+ @data << line << "\n"
298
+ end
299
+ end
300
+ end
301
+
302
+ def join
303
+ @thread.join
304
+ @data
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+
311
+
312
+ SystemU = SystemUniversal unless defined? SystemU
313
+ Systemu = SystemUniversal unless defined? Systemu
314
+
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+ if $0 == __FILE__
328
+ #
329
+ # date
330
+ #
331
+ date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
332
+
333
+ status, stdout, stderr = systemu date
334
+ p [status, stdout, stderr]
335
+
336
+ status = systemu date, 1=>(stdout = '')
337
+ p [status, stdout]
338
+
339
+ status = systemu date, 2=>(stderr = '')
340
+ p [status, stderr]
341
+ #
342
+ # sleep
343
+ #
344
+ sleep = %q( ruby -e" p(sleep(1)) " )
345
+ status, stdout, stderr = systemu sleep
346
+ p [status, stdout, stderr]
347
+
348
+ sleep = %q( ruby -e" p(sleep(42)) " )
349
+ status, stdout, stderr = systemu(sleep){|cid| Process.kill 9, cid}
350
+ p [status, stdout, stderr]
351
+ #
352
+ # env
353
+ #
354
+ env = %q( ruby -e" p ENV['A'] " )
355
+ status, stdout, stderr = systemu env, :env => {'A' => 42}
356
+ p [status, stdout, stderr]
357
+ #
358
+ # cwd
359
+ #
360
+ env = %q( ruby -e" p Dir.pwd " )
361
+ status, stdout, stderr = systemu env, :cwd => Dir.tmpdir
362
+ p [status, stdout, stderr]
363
+ end
@@ -0,0 +1,45 @@
1
+ ## systemu.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "systemu"
6
+ spec.version = "2.5.0"
7
+ spec.platform = Gem::Platform::RUBY
8
+ spec.summary = "systemu"
9
+ spec.description = "description: systemu kicks the ass"
10
+
11
+ spec.files =
12
+ ["LICENSE",
13
+ "README",
14
+ "README.erb",
15
+ "Rakefile",
16
+ "lib",
17
+ "lib/systemu.rb",
18
+ "samples",
19
+ "samples/a.rb",
20
+ "samples/b.rb",
21
+ "samples/c.rb",
22
+ "samples/d.rb",
23
+ "samples/e.rb",
24
+ "samples/f.rb",
25
+ "systemu.gemspec",
26
+ "test",
27
+ "test/systemu_test.rb",
28
+ "test/testing.rb"]
29
+
30
+ spec.executables = []
31
+
32
+ spec.require_path = "lib"
33
+
34
+ spec.test_files = nil
35
+
36
+ ### spec.add_dependency 'lib', '>= version'
37
+ #### spec.add_dependency 'map'
38
+
39
+ spec.extensions.push(*[])
40
+
41
+ spec.rubyforge_project = "codeforpeople"
42
+ spec.author = "Ara T. Howard"
43
+ spec.email = "ara.t.howard@gmail.com"
44
+ spec.homepage = "https://github.com/ahoward/systemu"
45
+ end
@@ -12,17 +12,17 @@ describe "Deploying an application without Bundler" do
12
12
 
13
13
  # run a deploy
14
14
  config = EY::Serverside::Deploy::Configuration.new({
15
- "strategy" => "IntegrationSpec",
16
- "deploy_to" => @deploy_dir.to_s,
17
- "group" => `id -gn`.strip,
18
- "stack" => 'nginx_passenger',
19
- "migrate" => nil,
20
- 'app' => 'foo',
21
- 'framework_env' => 'staging'
22
- })
15
+ "strategy" => "IntegrationSpec",
16
+ "deploy_to" => @deploy_dir.to_s,
17
+ "group" => `id -gn`.strip,
18
+ "stack" => 'nginx_passenger',
19
+ "migrate" => nil,
20
+ 'app' => 'foo',
21
+ 'framework_env' => 'staging'
22
+ })
23
23
 
24
24
  @binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
25
- @deployer = FullTestDeploy.new(config, test_shell)
25
+ @deployer = FullTestDeploy.new(config)
26
26
  @deployer.deploy
27
27
  end
28
28
 
@@ -32,7 +32,7 @@ describe "Deploying an application that uses Bundler" do
32
32
  end
33
33
 
34
34
  @binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
35
- @deployer = FullTestDeploy.new(config, test_shell)
35
+ @deployer = FullTestDeploy.new(config)
36
36
  @deployer.deploy
37
37
  end
38
38
 
@@ -11,6 +11,7 @@ describe "the EY::Serverside::Deploy API" do
11
11
  # cheat a bit; we don't actually want to do these things
12
12
  def require_custom_tasks() end
13
13
  def callback(*_) end
14
+ def puts(*_) 'stfu' end
14
15
 
15
16
  attr_reader :call_order
16
17
  def initialize(*a)
@@ -33,7 +34,7 @@ describe "the EY::Serverside::Deploy API" do
33
34
  def disable_maintenance_page() @call_order << 'disable_maintenance_page' end
34
35
  end
35
36
 
36
- td = TestDeploy.new(EY::Serverside::Deploy::Configuration.new, test_shell)
37
+ td = TestDeploy.new(EY::Serverside::Deploy::Configuration.new)
37
38
  td.deploy
38
39
  td.call_order.should == %w(
39
40
  push_code
@@ -51,66 +52,6 @@ describe "the EY::Serverside::Deploy API" do
51
52
  cleanup_old_releases)
52
53
  end
53
54
 
54
- describe "ey.yml loading" do
55
- before(:each) do
56
- @tempdir = `mktemp -d -t ey_yml_spec.XXXXX`.strip
57
- @config = EY::Serverside::Deploy::Configuration.new({
58
- 'repository_cache' => @tempdir,
59
- 'environment_name' => 'env_name',
60
- 'account_name' => 'acc',
61
- 'migrate' => nil,
62
- 'config' => {'branch' => 'branch_from_config'}.to_json
63
- })
64
-
65
- @deploy = FullTestDeploy.new(@config, test_shell)
66
-
67
- @yaml_data = {
68
- 'environments' => {
69
- 'env_name' => {
70
- 'copy_exclude' => ['.git'],
71
- 'migrate' => true,
72
- 'migration_command' => 'uh oh',
73
- 'branch' => 'branch_from_ey_yaml'
74
- }
75
- }
76
- }
77
- end
78
-
79
- def write_ey_yml(relative_path, data)
80
- FileUtils.mkdir_p(File.join(
81
- @tempdir,
82
- File.dirname(relative_path)))
83
-
84
- File.open(File.join(@tempdir, relative_path), 'w') do |f|
85
- f.write data.to_yaml
86
- end
87
- end
88
-
89
- it "requires 'ey.yml' and adds any defined methods to the deploy" do
90
- write_ey_yml 'ey.yml', @yaml_data
91
- @deploy.load_ey_yml
92
- @deploy.config.copy_exclude.should == ['.git']
93
- end
94
-
95
- it "falls back to 'config/ey.yml'" do
96
- write_ey_yml 'config/ey.yml', @yaml_data
97
- @deploy.load_ey_yml
98
- @deploy.config.copy_exclude.should == ['.git']
99
- end
100
-
101
- it "loads at lower priority than command line options" do
102
- write_ey_yml 'ey.yml', @yaml_data
103
- @deploy.load_ey_yml
104
- @deploy.config.migrate?.should == false
105
- end
106
-
107
- it "loads at lower priority than json config option" do
108
- write_ey_yml 'ey.yml', @yaml_data
109
- @deploy.load_ey_yml
110
- @deploy.config.branch.should == 'branch_from_config'
111
- end
112
- end
113
-
114
55
  describe "task overrides" do
115
56
  class TestQuietDeploy < EY::Serverside::Deploy
116
57
  def puts(*_) 'quiet' end
@@ -119,7 +60,7 @@ describe "the EY::Serverside::Deploy API" do
119
60
  before(:each) do
120
61
  @tempdir = `mktemp -d -t custom_deploy_spec.XXXXX`.strip
121
62
  @config = EY::Serverside::Deploy::Configuration.new('repository_cache' => @tempdir)
122
- @deploy = TestQuietDeploy.new(@config, test_shell)
63
+ @deploy = TestQuietDeploy.new(@config)
123
64
  end
124
65
 
125
66
  def write_eydeploy(relative_path, contents = "def got_new_methods() 'from the file on disk' end")
@@ -151,7 +92,7 @@ describe "the EY::Serverside::Deploy API" do
151
92
  def value() 'base' end
152
93
  end
153
94
 
154
- deploy = TestDeploySuper.new(@config, test_shell)
95
+ deploy = TestDeploySuper.new(@config)
155
96
  deploy.require_custom_tasks.should be_true
156
97
  deploy.value.should == "base + derived"
157
98
  end