engineyard-serverside 1.6.5 → 1.7.0.pre2
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.
- data/lib/engineyard-serverside.rb +2 -0
- data/lib/engineyard-serverside/cli.rb +83 -48
- data/lib/engineyard-serverside/configuration.rb +85 -18
- data/lib/engineyard-serverside/deploy.rb +105 -91
- data/lib/engineyard-serverside/deploy_hook.rb +22 -20
- data/lib/engineyard-serverside/deprecation.rb +9 -17
- data/lib/engineyard-serverside/future.rb +10 -4
- data/lib/engineyard-serverside/futures/celluloid.rb +3 -13
- data/lib/engineyard-serverside/futures/dataflow.rb +8 -13
- data/lib/engineyard-serverside/lockfile_parser.rb +1 -1
- data/lib/engineyard-serverside/rails_asset_support.rb +26 -10
- data/lib/engineyard-serverside/server.rb +17 -12
- data/lib/engineyard-serverside/shell.rb +98 -0
- data/lib/engineyard-serverside/shell/formatter.rb +71 -0
- data/lib/engineyard-serverside/shell/helpers.rb +29 -0
- data/lib/engineyard-serverside/strategies/git.rb +33 -63
- data/lib/engineyard-serverside/task.rb +34 -13
- data/lib/engineyard-serverside/version.rb +1 -1
- data/spec/basic_deploy_spec.rb +15 -50
- data/spec/bundler_deploy_spec.rb +3 -44
- data/spec/configuration_spec.rb +72 -0
- data/spec/custom_deploy_spec.rb +3 -4
- data/spec/deploy_hook_spec.rb +210 -162
- data/spec/deprecation_spec.rb +4 -26
- data/spec/ey_yml_customized_deploy_spec.rb +68 -0
- data/spec/fixtures/repos/assets_disabled/Gemfile +6 -0
- data/spec/fixtures/repos/assets_disabled/Gemfile.lock +90 -0
- data/spec/fixtures/repos/assets_disabled/README +1 -0
- data/spec/fixtures/repos/assets_disabled/Rakefile +5 -0
- data/spec/fixtures/repos/assets_disabled/config/application.rb +5 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile +6 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile.lock +90 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/README +1 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/Rakefile +5 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/config/application.rb +5 -0
- data/spec/fixtures/repos/assets_disabled_in_ey_yml/config/ey.yml +4 -0
- data/spec/fixtures/repos/assets_enabled/Gemfile +6 -0
- data/spec/fixtures/repos/assets_enabled/Gemfile.lock +90 -0
- data/spec/fixtures/repos/assets_enabled/README +1 -0
- data/spec/fixtures/repos/assets_enabled/Rakefile +5 -0
- data/spec/fixtures/repos/assets_enabled/config/application.rb +5 -0
- data/spec/fixtures/repos/assets_enabled_in_ey_yml/README +1 -0
- data/spec/fixtures/repos/assets_enabled_in_ey_yml/Rakefile +5 -0
- data/spec/fixtures/repos/assets_enabled_in_ey_yml/config/ey.yml +4 -0
- data/spec/fixtures/repos/assets_in_hook/Gemfile +6 -0
- data/spec/fixtures/repos/assets_in_hook/Gemfile.lock +90 -0
- data/spec/fixtures/repos/assets_in_hook/README +2 -0
- data/spec/fixtures/repos/assets_in_hook/Rakefile +5 -0
- data/spec/fixtures/repos/assets_in_hook/config/application.rb +5 -0
- data/spec/fixtures/repos/assets_in_hook/deploy/before_migrate.rb +1 -0
- data/spec/fixtures/repos/default/Gemfile +5 -0
- data/spec/fixtures/repos/default/Gemfile.lock +14 -0
- data/spec/fixtures/repos/default/README +5 -0
- data/spec/fixtures/repos/ey_yml/Gemfile +4 -0
- data/spec/fixtures/repos/ey_yml/Gemfile.lock +12 -0
- data/spec/fixtures/repos/ey_yml/README +1 -0
- data/spec/fixtures/repos/ey_yml/config/ey.yml +12 -0
- data/spec/fixtures/repos/ey_yml/deploy/before_migrate.rb +6 -0
- data/spec/fixtures/repos/ey_yml_alt/Gemfile +4 -0
- data/spec/fixtures/repos/ey_yml_alt/Gemfile.lock +12 -0
- data/spec/fixtures/repos/ey_yml_alt/README +1 -0
- data/spec/fixtures/repos/ey_yml_alt/deploy/before_migrate.rb +6 -0
- data/spec/fixtures/repos/ey_yml_alt/ey.yml +12 -0
- data/spec/fixtures/repos/hook_fails/README +1 -0
- data/spec/fixtures/repos/hook_fails/deploy/before_migrate.rb +1 -0
- data/spec/fixtures/repos/hooks/README +1 -0
- data/spec/fixtures/repos/hooks/deploy/after_bundle.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/after_compile_assets.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/after_migrate.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/after_restart.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/after_symlink.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/before_bundle.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/before_compile_assets.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/before_migrate.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/before_restart.rb +1 -0
- data/spec/fixtures/repos/hooks/deploy/before_symlink.rb +1 -0
- data/spec/fixtures/repos/no_ey_config/Gemfile +4 -0
- data/spec/fixtures/repos/no_ey_config/Gemfile.lock +12 -0
- data/spec/fixtures/repos/no_ey_config/README +1 -0
- data/spec/fixtures/repos/no_gemfile_lock/Gemfile +5 -0
- data/spec/fixtures/repos/no_gemfile_lock/README +1 -0
- data/spec/fixtures/repos/nodejs/README +1 -0
- data/spec/fixtures/repos/nodejs/package.json +7 -0
- data/spec/fixtures/repos/not_bundled/README +1 -0
- data/spec/fixtures/{gemfiles/1.0.21-rails-31-with-sqlite → repos/sqlite3/Gemfile} +0 -0
- data/spec/fixtures/{lockfiles/1.0.21-rails-31-with-sqlite → repos/sqlite3/Gemfile.lock} +0 -0
- data/spec/fixtures/repos/sqlite3/README +1 -0
- data/spec/git_strategy_spec.rb +11 -2
- data/spec/lockfile_parser_spec.rb +8 -3
- data/spec/nodejs_deploy_spec.rb +1 -26
- data/spec/rails31_deploy_spec.rb +23 -31
- data/spec/services_deploy_spec.rb +41 -100
- data/spec/shell_spec.rb +50 -0
- data/spec/spec_helper.rb +80 -66
- data/spec/sqlite3_deploy_spec.rb +10 -16
- data/spec/support/integration.rb +45 -139
- metadata +233 -78
- data/lib/engineyard-serverside/logged_output.rb +0 -91
- data/spec/logged_output_spec.rb +0 -55
|
@@ -1,41 +1,51 @@
|
|
|
1
|
+
require 'engineyard-serverside/shell/helpers'
|
|
2
|
+
|
|
1
3
|
module EY
|
|
2
4
|
module Serverside
|
|
3
5
|
class DeployHook < Task
|
|
4
|
-
def initialize(options)
|
|
5
|
-
super(EY::Serverside::Deploy::Configuration.new(options))
|
|
6
|
-
end
|
|
7
|
-
|
|
8
6
|
def callback_context
|
|
9
|
-
@context ||= CallbackContext.new(config)
|
|
7
|
+
@context ||= CallbackContext.new(config, shell)
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def run(hook)
|
|
13
11
|
hook_path = "#{c.release_path}/deploy/#{hook}.rb"
|
|
14
12
|
if File.exist?(hook_path)
|
|
15
13
|
Dir.chdir(c.release_path) do
|
|
16
|
-
puts "~> running deploy hook: deploy/#{hook}.rb"
|
|
17
14
|
if desc = syntax_error(hook_path)
|
|
18
15
|
hook_name = File.basename(hook_path)
|
|
19
16
|
abort "*** [Error] Invalid Ruby syntax in hook: #{hook_name} ***\n*** #{desc.chomp} ***"
|
|
20
17
|
else
|
|
21
|
-
|
|
18
|
+
eval_hook(IO.read(hook_path))
|
|
22
19
|
end
|
|
23
20
|
end
|
|
24
21
|
end
|
|
25
22
|
end
|
|
26
23
|
|
|
24
|
+
def eval_hook(code)
|
|
25
|
+
callback_context.instance_eval(code)
|
|
26
|
+
end
|
|
27
|
+
|
|
27
28
|
def syntax_error(file)
|
|
28
29
|
output = `ruby -c #{file} 2>&1`
|
|
29
30
|
output unless output =~ /Syntax OK/
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
class CallbackContext
|
|
33
|
-
|
|
34
|
+
include EY::Serverside::Shell::Helpers
|
|
35
|
+
|
|
36
|
+
attr_reader :shell
|
|
37
|
+
|
|
38
|
+
def initialize(config, shell)
|
|
34
39
|
@configuration = config
|
|
35
40
|
@configuration.set_framework_envs
|
|
41
|
+
@shell = shell
|
|
36
42
|
@node = node
|
|
37
43
|
end
|
|
38
44
|
|
|
45
|
+
def config
|
|
46
|
+
@configuration
|
|
47
|
+
end
|
|
48
|
+
|
|
39
49
|
def method_missing(meth, *args, &blk)
|
|
40
50
|
if @configuration.respond_to?(meth)
|
|
41
51
|
@configuration.send(meth, *args, &blk)
|
|
@@ -44,24 +54,16 @@ module EY
|
|
|
44
54
|
end
|
|
45
55
|
end
|
|
46
56
|
|
|
47
|
-
def respond_to?(
|
|
48
|
-
@configuration.respond_to?(
|
|
57
|
+
def respond_to?(*a)
|
|
58
|
+
@configuration.respond_to?(*a) || super
|
|
49
59
|
end
|
|
50
60
|
|
|
51
61
|
def run(cmd)
|
|
52
|
-
|
|
62
|
+
shell.logged_system(Escape.shell_command(["sh", "-l", "-c", cmd])).success?
|
|
53
63
|
end
|
|
54
64
|
|
|
55
65
|
def sudo(cmd)
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def info(*args)
|
|
60
|
-
$stderr.puts *args
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def debug(*args)
|
|
64
|
-
$stdout.puts *args
|
|
66
|
+
shell.logged_system(Escape.shell_command(["sudo", "sh", "-l", "-c", cmd])).success?
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
# convenience functions for running on certain instance types
|
|
@@ -1,26 +1,18 @@
|
|
|
1
|
+
require 'engineyard-serverside/shell/helpers'
|
|
2
|
+
|
|
1
3
|
module EY
|
|
2
4
|
module Serverside
|
|
3
5
|
def self.deprecation_warning(msg)
|
|
4
6
|
$stderr.puts "DEPRECATION WARNING: #{msg}"
|
|
5
7
|
end
|
|
6
|
-
end
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
def self.const_missing(const)
|
|
10
|
+
if const == :LoggedOutput
|
|
11
|
+
EY::Serverside.deprecation_warning("EY::Serverside::LoggedOutput has been deprecated. Use EY::Serverside::Shell::Helpers instead.")
|
|
12
|
+
EY::Serverside::Shell::Helpers
|
|
13
|
+
else
|
|
14
|
+
super
|
|
15
|
+
end
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
|
-
|
|
17
|
-
def self.node
|
|
18
|
-
EY::Serverside.deprecation_warning("EY.node has been deprecated. use EY::Serverside.node instead")
|
|
19
|
-
EY::Serverside.node
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.dna_json
|
|
23
|
-
EY::Serverside.deprecation_warning("EY.dna_json has been deprecated. use EY::Serverside.dna_json instead")
|
|
24
|
-
EY::Serverside.dna_json
|
|
25
|
-
end
|
|
26
18
|
end
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
module EY
|
|
2
2
|
module Serverside
|
|
3
3
|
class Future
|
|
4
|
+
def self.map(blocks)
|
|
5
|
+
blocks.map { |block| new(&block) }
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
def self.success?(futures)
|
|
5
9
|
futures.empty? || futures.all? {|f| f.success?}
|
|
6
10
|
end
|
|
7
11
|
|
|
8
|
-
def initialize(
|
|
9
|
-
@server = server
|
|
10
|
-
@args = args
|
|
12
|
+
def initialize(&block)
|
|
11
13
|
@block = block
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
def result
|
|
17
|
+
@result ||= call
|
|
18
|
+
end
|
|
19
|
+
|
|
14
20
|
def success?
|
|
15
|
-
|
|
21
|
+
result.success?
|
|
16
22
|
end
|
|
17
23
|
|
|
18
24
|
def error?
|
|
@@ -3,22 +3,12 @@ module EY
|
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path('../../vendor/celluloid/lib', File.dirname(__FILE__))
|
|
4
4
|
require 'celluloid'
|
|
5
5
|
class Future
|
|
6
|
-
def self.call(
|
|
7
|
-
|
|
8
|
-
new(server, *args, &block)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
futures.each {|f| f.call}
|
|
12
|
-
futures
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def future
|
|
16
|
-
Celluloid::Future.new(@server, *@args, &@block)
|
|
6
|
+
def self.call(blocks)
|
|
7
|
+
map(blocks).each {|f| f.result }
|
|
17
8
|
end
|
|
18
9
|
|
|
19
10
|
def call
|
|
20
|
-
|
|
21
|
-
@value ||= future.call
|
|
11
|
+
Celluloid::Future.new(&@block).call
|
|
22
12
|
end
|
|
23
13
|
end
|
|
24
14
|
end
|
|
@@ -6,25 +6,20 @@ module EY
|
|
|
6
6
|
class Future
|
|
7
7
|
extend Dataflow
|
|
8
8
|
|
|
9
|
-
def self.call(
|
|
10
|
-
futures =
|
|
11
|
-
# Dataflow needs to call `barrier` and `need_later` in the same object
|
|
12
|
-
barrier(*servers.map do |server|
|
|
13
|
-
future = new(server, *args, &block)
|
|
14
|
-
futures << future
|
|
9
|
+
def self.call(blocks)
|
|
10
|
+
futures = map(blocks)
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
# Dataflow needs to call `barrier` and `need_later` in the same object
|
|
13
|
+
need_laters = futures.map do |future|
|
|
14
|
+
need_later { future.result }
|
|
15
|
+
end
|
|
16
|
+
barrier(*need_laters)
|
|
18
17
|
|
|
19
18
|
futures
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
def future
|
|
23
|
-
@block.call(@server, *@args)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
21
|
def call
|
|
27
|
-
@
|
|
22
|
+
@block.call
|
|
28
23
|
end
|
|
29
24
|
end
|
|
30
25
|
end
|
|
@@ -2,44 +2,60 @@ module EY
|
|
|
2
2
|
module Serverside
|
|
3
3
|
module RailsAssetSupport
|
|
4
4
|
def compile_assets
|
|
5
|
-
asset_dir = "#{c.release_path}/app/assets"
|
|
6
5
|
return unless app_needs_assets?
|
|
7
6
|
rails_version = bundled_rails_version
|
|
8
7
|
roles :app_master, :app, :solo do
|
|
9
8
|
keep_existing_assets
|
|
10
|
-
cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake assets:precompile
|
|
9
|
+
cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake assets:precompile"
|
|
10
|
+
|
|
11
|
+
unless config.precompile_assets?
|
|
12
|
+
# If specifically requested, then we want to fail if compilation fails.
|
|
13
|
+
# If we are implicitly precompiling, we want to fail non-destructively
|
|
14
|
+
# because we don't know if the rake task exists or if the user
|
|
15
|
+
# actually intended for assets to be compiled.
|
|
16
|
+
cmd << %{ || (echo "Asset compilation failure ignored.\n Add 'precompile_assets: true' to ey.yml to abort deploy on failure." && true)}
|
|
17
|
+
end
|
|
18
|
+
|
|
11
19
|
if rails_version
|
|
12
|
-
|
|
20
|
+
shell.status "Precompiling assets for rails v#{rails_version}"
|
|
13
21
|
else
|
|
14
|
-
warning "Precompiling assets even though Rails was not bundled."
|
|
22
|
+
shell.warning "Precompiling assets even though Rails was not bundled."
|
|
15
23
|
end
|
|
16
24
|
run(cmd)
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
def app_needs_assets?
|
|
29
|
+
if config.precompile_assets?
|
|
30
|
+
shell.status "Attempting Rails asset precompilation. (enabled in config)"
|
|
31
|
+
return true
|
|
32
|
+
elsif config.skip_precompile_assets?
|
|
33
|
+
shell.status "Skipping asset precompilation. (disabled in config)"
|
|
34
|
+
return false
|
|
35
|
+
end
|
|
36
|
+
|
|
21
37
|
app_rb_path = File.join(c.release_path, 'config', 'application.rb')
|
|
22
38
|
return unless File.readable?(app_rb_path) # Not a Rails app in the first place.
|
|
23
39
|
|
|
24
40
|
if File.directory?(File.join(c.release_path, 'app', 'assets'))
|
|
25
|
-
|
|
41
|
+
shell.status "Attempting Rails asset precompilation. (found directory: 'app/assets')"
|
|
26
42
|
else
|
|
27
43
|
return false
|
|
28
44
|
end
|
|
29
45
|
|
|
30
46
|
if app_builds_own_assets?
|
|
31
|
-
|
|
47
|
+
shell.status "Skipping asset compilation. (found directory: 'public/assets')"
|
|
32
48
|
return
|
|
33
49
|
end
|
|
34
50
|
if app_disables_assets?(app_rb_path)
|
|
35
|
-
|
|
51
|
+
shell.status "Skipping asset compilation. (application.rb has disabled asset compilation)"
|
|
36
52
|
return
|
|
37
53
|
end
|
|
38
54
|
# This check is very expensive, and has been deemed not worth the time.
|
|
39
55
|
# Leaving this here in case someone comes up with a faster way.
|
|
40
56
|
=begin
|
|
41
57
|
unless app_has_asset_task?
|
|
42
|
-
|
|
58
|
+
shell.status "No 'assets:precompile' Rake task found. Skipping."
|
|
43
59
|
return
|
|
44
60
|
end
|
|
45
61
|
=end
|
|
@@ -62,8 +78,7 @@ module EY
|
|
|
62
78
|
# have the same code anyway.
|
|
63
79
|
task_check = "PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake -T assets:precompile |grep 'assets:precompile'"
|
|
64
80
|
cmd = "cd #{c.release_path} && #{task_check}"
|
|
65
|
-
logged_system
|
|
66
|
-
$? == 0
|
|
81
|
+
shell.logged_system("cd #{c.release_path} && #{task_check}").success?
|
|
67
82
|
end
|
|
68
83
|
|
|
69
84
|
def app_builds_own_assets?
|
|
@@ -90,6 +105,7 @@ ln -nfs #{current} #{last_asset_path} #{c.release_path}/public
|
|
|
90
105
|
|
|
91
106
|
def bundled_rails_version(lockfile_path = nil)
|
|
92
107
|
lockfile_path ||= File.join(c.release_path, 'Gemfile.lock')
|
|
108
|
+
return unless File.exist?(lockfile_path)
|
|
93
109
|
lockfile = File.open(lockfile_path) {|f| f.read}
|
|
94
110
|
lockfile.each_line do |line|
|
|
95
111
|
# scan for gemname (version) toplevel deps.
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
require 'open-uri'
|
|
2
|
-
require 'engineyard-serverside/logged_output'
|
|
3
2
|
|
|
4
3
|
module EY
|
|
5
4
|
module Serverside
|
|
6
5
|
class Server < Struct.new(:hostname, :roles, :name, :user)
|
|
7
|
-
include LoggedOutput
|
|
8
|
-
|
|
9
6
|
class DuplicateHostname < StandardError
|
|
10
7
|
def initialize(hostname)
|
|
11
8
|
super "There is already an EY::Serverside::Server with hostname '#{hostname}'"
|
|
@@ -73,18 +70,26 @@ module EY
|
|
|
73
70
|
hostname == 'localhost'
|
|
74
71
|
end
|
|
75
72
|
|
|
76
|
-
def
|
|
77
|
-
return if local?
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
def sync_directory_command(directory)
|
|
74
|
+
return nil if local?
|
|
75
|
+
[
|
|
76
|
+
remote_command("mkdir -p #{directory}"),
|
|
77
|
+
Escape.shell_command(%w[rsync --delete -aq -e] + [ssh_command, "#{directory}/", "#{user}@#{hostname}:#{directory}"])
|
|
78
|
+
].join(' && ')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def command_on_server(prefix, cmd, &block)
|
|
82
|
+
command = block ? block.call(self, cmd.dup) : cmd
|
|
83
|
+
command = "#{prefix} #{Escape.shell_command([command])}"
|
|
84
|
+
local? ? command : remote_command(command)
|
|
80
85
|
end
|
|
81
86
|
|
|
82
87
|
def run(command)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
yield local? ? command : remote_command(command)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def remote_command(command)
|
|
92
|
+
ssh_command + Escape.shell_command(["#{user}@#{hostname}", command])
|
|
88
93
|
end
|
|
89
94
|
|
|
90
95
|
# Make a known hosts tempfile to absorb host fingerprints so we don't show
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'pathname'
|
|
3
|
+
require 'systemu'
|
|
4
|
+
require 'engineyard-serverside/shell/formatter'
|
|
5
|
+
|
|
6
|
+
module EY
|
|
7
|
+
module Serverside
|
|
8
|
+
class Shell
|
|
9
|
+
class YieldIO
|
|
10
|
+
def initialize(&block)
|
|
11
|
+
@block = block
|
|
12
|
+
end
|
|
13
|
+
def <<(str)
|
|
14
|
+
@block.call str
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class CommandResult < Struct.new(:command, :exitstatus, :output)
|
|
19
|
+
def success?
|
|
20
|
+
exitstatus.zero?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def inspect
|
|
24
|
+
<<-EOM
|
|
25
|
+
$ #{command}
|
|
26
|
+
#{output}
|
|
27
|
+
|
|
28
|
+
# => #{exitstatus}
|
|
29
|
+
EOM
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
attr_reader :logger
|
|
34
|
+
|
|
35
|
+
def initialize(options)
|
|
36
|
+
@start_time = options[:start_time]
|
|
37
|
+
@verbose = options[:verbose]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@stdout = options[:stdout] || $stdout
|
|
41
|
+
@stderr = options[:stderr] || $stderr
|
|
42
|
+
|
|
43
|
+
log_pathname = Pathname.new(options[:log_path])
|
|
44
|
+
log_pathname.unlink if log_pathname.exist? # start fresh
|
|
45
|
+
@logger = Logger.new(log_pathname.to_s)
|
|
46
|
+
@logger.level = Logger::DEBUG # Always log to the file at debug, formatter hides debug for non-verbose
|
|
47
|
+
@logger.formatter = EY::Serverside::Shell::Formatter.new(@stdout, @stderr, start_time, @verbose)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def start_time
|
|
51
|
+
@start_time ||= Time.now
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# a nice info outputter that prepends spermy operators for some reason.
|
|
55
|
+
def status(msg)
|
|
56
|
+
info msg.gsub(/^/, '~> ')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def substatus(msg)
|
|
60
|
+
debug msg.gsub(/^/, ' ~ ')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def fatal(msg) logger.fatal "FATAL: #{msg}" end
|
|
64
|
+
def error(msg) logger.error "ERROR: #{msg}" end
|
|
65
|
+
def warning(msg) logger.warn "WARNING: #{msg}" end
|
|
66
|
+
def notice(msg) logger.warn msg end
|
|
67
|
+
def info(msg) logger.info msg end
|
|
68
|
+
def debug(msg) logger.debug msg end
|
|
69
|
+
def unknown(msg) logger.unknown msg end
|
|
70
|
+
|
|
71
|
+
# a debug outputter that displays a command being run
|
|
72
|
+
# Formatis like this:
|
|
73
|
+
# $ cmd blah do \
|
|
74
|
+
# > something more
|
|
75
|
+
# > end
|
|
76
|
+
def show_command(cmd)
|
|
77
|
+
debug cmd.gsub(/^/, ' > ').sub(/>/, '$')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def logged_system(cmd)
|
|
81
|
+
show_command(cmd)
|
|
82
|
+
output = ""
|
|
83
|
+
outio = YieldIO.new { |msg| output << msg; debug msg.gsub(/^/,' ') }
|
|
84
|
+
errio = YieldIO.new { |msg| output << msg; unknown msg.gsub(/^/,' ') }
|
|
85
|
+
result = spawn_process(cmd, outio, errio)
|
|
86
|
+
CommandResult.new(cmd, result.exitstatus, output)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
protected
|
|
90
|
+
|
|
91
|
+
# This is the meat of process spawning. It's nice to keep it separate even
|
|
92
|
+
# though it's simple because we've had to modify it frequently.
|
|
93
|
+
def spawn_process(cmd, outio, errio)
|
|
94
|
+
systemu cmd, 'stdout' => outio, 'stderr' => errio
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|