engineyard-serverside 1.6.0.pre5 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,51 +1,40 @@
1
- require 'engineyard-serverside/shell/helpers'
2
-
3
1
  module EY
4
2
  module Serverside
5
3
  class DeployHook < Task
4
+ def initialize(options)
5
+ super(EY::Serverside::Deploy::Configuration.new(options))
6
+ end
7
+
6
8
  def callback_context
7
- @context ||= CallbackContext.new(config, shell)
9
+ @context ||= CallbackContext.new(config)
8
10
  end
9
11
 
10
12
  def run(hook)
11
13
  hook_path = "#{c.release_path}/deploy/#{hook}.rb"
12
14
  if File.exist?(hook_path)
13
15
  Dir.chdir(c.release_path) do
14
- shell.status "Running deploy hook: deploy/#{hook}.rb"
16
+ puts "~> running deploy hook: deploy/#{hook}.rb"
15
17
  if desc = syntax_error(hook_path)
16
18
  hook_name = File.basename(hook_path)
17
19
  abort "*** [Error] Invalid Ruby syntax in hook: #{hook_name} ***\n*** #{desc.chomp} ***"
18
20
  else
19
- eval_hook(IO.read(hook_path))
21
+ callback_context.instance_eval(IO.read(hook_path))
20
22
  end
21
23
  end
22
24
  end
23
25
  end
24
26
 
25
- def eval_hook(code)
26
- callback_context.instance_eval(code)
27
- end
28
-
29
27
  def syntax_error(file)
30
28
  output = `ruby -c #{file} 2>&1`
31
29
  output unless output =~ /Syntax OK/
32
30
  end
33
31
 
34
32
  class CallbackContext
35
- include EY::Serverside::Shell::Helpers
36
-
37
- attr_reader :shell
38
-
39
- def initialize(config, shell)
33
+ def initialize(config)
40
34
  @configuration = config
41
- @shell = shell
42
35
  @node = node
43
36
  end
44
37
 
45
- def config
46
- @configuration
47
- end
48
-
49
38
  def method_missing(meth, *args, &blk)
50
39
  if @configuration.respond_to?(meth)
51
40
  @configuration.send(meth, *args, &blk)
@@ -59,11 +48,19 @@ module EY
59
48
  end
60
49
 
61
50
  def run(cmd)
62
- shell.logged_system(Escape.shell_command(["sh", "-l", "-c", cmd]))
51
+ system(Escape.shell_command(["sh", "-l", "-c", cmd]))
63
52
  end
64
53
 
65
54
  def sudo(cmd)
66
- shell.logged_system(Escape.shell_command(["sudo", "sh", "-l", "-c", cmd]))
55
+ system(Escape.shell_command(["sudo", "sh", "-l", "-c", cmd]))
56
+ end
57
+
58
+ def info(*args)
59
+ $stderr.puts *args
60
+ end
61
+
62
+ def debug(*args)
63
+ $stdout.puts *args
67
64
  end
68
65
 
69
66
  # convenience functions for running on certain instance types
@@ -1,18 +1,26 @@
1
- require 'engineyard-serverside/shell/helpers'
2
-
3
1
  module EY
4
2
  module Serverside
5
3
  def self.deprecation_warning(msg)
6
4
  $stderr.puts "DEPRECATION WARNING: #{msg}"
7
5
  end
6
+ end
8
7
 
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
8
+ def self.const_missing(const)
9
+ if EY::Serverside.const_defined?(const)
10
+ EY::Serverside.deprecation_warning("EY::#{const} has been deprecated. use EY::Serverside::#{const} instead")
11
+ EY::Serverside.class_eval(const.to_s)
12
+ else
13
+ super
16
14
  end
17
15
  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
18
26
  end
@@ -24,7 +24,7 @@ module EY
24
24
  @contents.index(/^\s+#{type}\s\([^\)]+\)$/)
25
25
  end
26
26
 
27
- any_jruby_adapter = %w[mysql postgresql].any? do |type|
27
+ any_jruby_adapter = %w[mysql postgresql postgres].any? do |type|
28
28
  @contents.index(/^\s+jdbc-#{type}\s\([^\)]+\)$/) || @contents.index(/^\s+activerecord-jdbc#{type}-adapter\s\([^\)]+\)$/)
29
29
  end
30
30
 
@@ -0,0 +1,91 @@
1
+ require 'systemu'
2
+
3
+ module EY
4
+ module Serverside
5
+ module LoggedOutput
6
+
7
+ class Tee
8
+ def initialize(*streams)
9
+ @streams = streams.flatten
10
+ end
11
+
12
+ def <<(output)
13
+ @streams.each do |s|
14
+ s << output
15
+ s.flush
16
+ end
17
+ self
18
+ end
19
+ end # Tee
20
+
21
+ @@logfile = File.join(ENV['HOME'], 'ey.log')
22
+ def self.logfile=(filename)
23
+ File.unlink filename if File.exist?(filename) # start fresh
24
+ @@logfile = filename
25
+ end
26
+
27
+ def self.logfile
28
+ @@logfile
29
+ end
30
+
31
+ @@verbose = false
32
+ def self.verbose=(v)
33
+ @@verbose = !!v
34
+ end
35
+
36
+ def self.verbose?
37
+ @@verbose
38
+ end
39
+
40
+ def verbose?
41
+ EY::Serverside::LoggedOutput.verbose?
42
+ end
43
+
44
+ def warning(msg)
45
+ info "WARNING: #{msg}\n".gsub(/^/,'!> ')
46
+ end
47
+
48
+ def info(msg)
49
+ with_logfile do |log|
50
+ Tee.new($stdout, log) << ("#{with_timestamp(msg)}\n")
51
+ end
52
+ end
53
+
54
+ def debug(msg)
55
+ with_logfile do |log|
56
+ log << "#{with_timestamp(msg)}\n"
57
+ end
58
+ end
59
+
60
+ def logged_system(cmd)
61
+ with_logfile do |log|
62
+ out = verbose? ? Tee.new($stdout, log) : log
63
+ err = Tee.new($stderr, log) # we always want to see errors
64
+
65
+ cmd = "sh -c #{Escape.shell_command([cmd])}"
66
+ puts "running #{cmd}" if ENV['DEBUG']
67
+ out << with_timestamp(":: running #{cmd}\n")
68
+ status = systemu cmd, 'stdout' => out, 'stderr' => err
69
+ puts "exit status= #{status.exitstatus}" if ENV['DEBUG']
70
+ status.exitstatus == 0
71
+ end
72
+ end
73
+
74
+ private
75
+ def with_logfile
76
+ File.open(logfile, 'a') {|f| yield f }
77
+ end
78
+
79
+ def logfile
80
+ EY::Serverside::LoggedOutput.logfile
81
+ end
82
+
83
+ def with_timestamp(msg)
84
+ return msg unless respond_to?(:starting_time)
85
+ time_passed = Time.now.to_i - starting_time.to_i
86
+ timestamp = "+%2dm %02ds " % time_passed.divmod(60)
87
+ msg.gsub(/^/, timestamp)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -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}'"
@@ -72,20 +75,20 @@ module EY
72
75
 
73
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} #{user}@#{hostname} #{Escape.shell_command [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 UserKnownHostsFile=/dev/null -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/helpers'
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
@@ -30,25 +26,6 @@ module EY
30
26
  end
31
27
  end
32
28
 
33
- def load_ey_yml
34
- ey_yml = ["config/ey.yml", "ey.yml"].map do |short_file|
35
- File.join(c.repository_cache, short_file)
36
- end.detect do |file|
37
- File.exist?(file)
38
- end
39
-
40
- if ey_yml
41
- shell.status "Loading deploy configuration in #{ey_yml}"
42
- data = YAML.load_file(ey_yml)
43
- config.ey_yml_data = data
44
- else
45
- false
46
- end
47
- rescue Exception
48
- shell.error "Error loading YAML in #{ey_yml}"
49
- raise
50
- end
51
-
52
29
  def roles(*task_roles)
53
30
  raise "Roles must be passed a block" unless block_given?
54
31
 
@@ -68,16 +45,18 @@ module EY
68
45
  end
69
46
 
70
47
  def sudo(cmd, &blk)
71
- run_on_roles(cmd, %w[sudo sh -l -c], &blk)
48
+ sudo_cmd = "sudo sh -c #{Escape.shell_command [cmd]}"
49
+
50
+ run_on_roles(sudo_cmd, &blk)
72
51
  end
73
52
 
74
53
  private
75
54
 
76
- def run_on_roles(cmd, wrapper=%w[sh -l -c], &block)
55
+ def run_on_roles(cmd, &block)
77
56
  servers = EY::Serverside::Server.from_roles(@roles)
78
57
  futures = EY::Serverside::Future.call(servers, block_given?) do |server, exec_block|
79
58
  to_run = exec_block ? block.call(server, cmd.dup) : cmd
80
- server.run(Escape.shell_command(wrapper + [to_run])) { |cmd| shell.logged_system(cmd) }
59
+ server.run(to_run)
81
60
  end
82
61
 
83
62
  unless EY::Serverside::Future.success?(futures)
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '1.6.0.pre5'
3
+ VERSION = '1.6.3'
4
4
  end
5
5
  end
@@ -0,0 +1,3 @@
1
+ same as Ruby's
2
+
3
+ http://www.ruby-lang.org/en/LICENSE.txt