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
@@ -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