engineyard-local 0.2.1 → 1.0.1

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 (44) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +73 -1
  3. data/README.md +40 -38
  4. data/config/dna.json +92 -66
  5. data/config/locales/en.yml +94 -9
  6. data/config/patches/chef-ey-1.1.336.patch +55 -0
  7. data/config/settings.yml +6 -1
  8. data/engineyard-local.gemspec +5 -4
  9. data/install/osx/README.md +42 -4
  10. data/install/osx/engineyard-local/engineyard-local.pkgproj +35 -6
  11. data/install/osx/images/dmg_background.png +0 -0
  12. data/install/osx/images/dmg_icon.icns +0 -0
  13. data/lib/engineyard-local.rb +64 -0
  14. data/lib/engineyard-local/command.rb +23 -0
  15. data/lib/engineyard-local/command/base.rb +78 -1
  16. data/lib/engineyard-local/command/group.rb +70 -6
  17. data/lib/engineyard-local/command/help.rb +36 -0
  18. data/lib/engineyard-local/command/helpers.rb +12 -0
  19. data/lib/engineyard-local/command/start.rb +26 -0
  20. data/lib/engineyard-local/command/status.rb +33 -0
  21. data/lib/engineyard-local/command/stop.rb +26 -0
  22. data/lib/engineyard-local/command/terminate.rb +26 -0
  23. data/lib/engineyard-local/command/up.rb +24 -15
  24. data/lib/engineyard-local/command/update.rb +42 -0
  25. data/lib/engineyard-local/middleware.rb +1 -0
  26. data/lib/engineyard-local/middleware/bundle.rb +1 -0
  27. data/lib/engineyard-local/middleware/chef.rb +52 -2
  28. data/lib/engineyard-local/middleware/cookbooks.rb +111 -0
  29. data/lib/engineyard-local/middleware/dna.rb +6 -4
  30. data/lib/engineyard-local/middleware/exec.rb +2 -1
  31. data/lib/engineyard-local/middleware/helpers/executable.rb +14 -2
  32. data/lib/engineyard-local/middleware/network.rb +3 -3
  33. data/lib/engineyard-local/middleware/rails.rb +1 -0
  34. data/lib/engineyard-local/middleware/rails/assets.rb +35 -0
  35. data/lib/engineyard-local/middleware/rails/command.rb +1 -1
  36. data/lib/engineyard-local/middleware/rails/db.rb +0 -1
  37. data/lib/engineyard-local/middleware/rails/new.rb +1 -1
  38. data/lib/engineyard-local/version.rb +1 -1
  39. data/test/engineyard-local/command/up_test.rb +1 -0
  40. data/test/integration/commands_test.rb +30 -0
  41. data/test/test_helper.rb +8 -2
  42. metadata +81 -70
  43. data/install/osx/images/eylocal_installer.png +0 -0
  44. data/test/integration/up_test.rb +0 -28
@@ -1,6 +1,7 @@
1
1
  module Engineyard
2
2
  module Local
3
3
  module Command
4
+
4
5
  def self.all
5
6
  Engineyard::Local.locales[:commands].keys.map { |cmd| cmd.to_s }
6
7
  end
@@ -53,6 +54,14 @@ module Engineyard
53
54
  end
54
55
  end
55
56
 
57
+ module Vagrant
58
+ class CLI
59
+ def help
60
+ Engineyard::Local::Command.dispatch(['help'])
61
+ end
62
+ end
63
+ end
64
+
56
65
  require "thor"
57
66
  # TODO autoload
58
67
  require "engineyard-local/command/helpers"
@@ -63,3 +72,17 @@ require "engineyard-local/command/exec"
63
72
  require "engineyard-local/command/list"
64
73
  require "engineyard-local/command/rails"
65
74
  require "engineyard-local/command/up"
75
+ require "engineyard-local/command/status"
76
+ require "engineyard-local/command/help"
77
+ require "engineyard-local/command/update"
78
+ require "engineyard-local/command/start"
79
+ require "engineyard-local/command/stop"
80
+ require "engineyard-local/command/terminate"
81
+
82
+ module Engineyard
83
+ module Local
84
+ module Command
85
+ COMMANDS_WITH_NO_COOKBOOK_CHECK = [Engineyard::Local::Command::Terminate, Engineyard::Local::Command::Status, Engineyard::Local::Command::Update, Vagrant::Command::Suspend, Vagrant::Command::Halt]
86
+ end
87
+ end
88
+ end
@@ -1,13 +1,90 @@
1
+ module Vagrant
2
+ module Command
3
+ class Base
4
+ include Engineyard::Local::Command::Helpers
5
+
6
+ def cookbook_status(scope = :partial, get_installed_version = true)
7
+ installed_cookbook_version = []
8
+ la_brea_data = []
9
+ cb_status = ''
10
+
11
+ begin
12
+ run( Vagrant::Action::Builder.new do
13
+ use( Engineyard::Local::Middleware::Cookbooks,:get_installed_version, installed_cookbook_version ) if get_installed_version
14
+ use( Engineyard::Local::Middleware::Cookbooks,:get_la_brea_data, la_brea_data )
15
+ end )
16
+ rescue Exception
17
+ cookbooks_status = "ERROR: Failure while determining cookbook status."
18
+ end
19
+
20
+ installed_cookbook_version = installed_cookbook_version.first
21
+ la_brea_data = la_brea_data.first || {}
22
+
23
+ if ( installed_cookbook_version == la_brea_data[:cookbooks_version] ) && ( scope == :full )
24
+ cb_status << I18n.t("vagrant.commands.status.cookbooks_current",
25
+ :version => installed_cookbook_version)
26
+ elsif ( installed_cookbook_version != la_brea_data[:cookbooks_version] )
27
+ cb_status << I18n.t("vagrant.commands.status.cookbooks_outdated",
28
+ :version => installed_cookbook_version,
29
+ :new_version => la_brea_data[:cookbooks_version],
30
+ :changelog => Nokogiri::HTML(la_brea_data[:changelog]).text)
31
+ end
32
+
33
+ cb_status
34
+ end
35
+
36
+ def initialize(argv, env)
37
+ @argv = argv
38
+ @env = env
39
+ @logger = Log4r::Logger.new("vagrant::command::#{self.class.to_s.downcase}")
40
+ @cookbook_status_already_checked ||= :not_checked
41
+
42
+ begin
43
+ with_target_vms() do |vm|
44
+ if vm.created? && vm.state == :running
45
+ @env.ui.info(cookbook_status, :prefix => false) unless Engineyard::Local.cookbook_version_verified?
46
+ Engineyard::Local.cookbook_version_verified
47
+ else
48
+ cookbook_status(:partial, false)
49
+ end
50
+ end
51
+ rescue Errors::NoEnvironmentError
52
+ # Ignore this error. It will happen any time an ey-local/vagrant command is invoked
53
+ # in a directory that is not yet setup with a Vagrant environment.
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+
1
61
  module Engineyard
2
62
  module Local
3
63
  module Command
4
64
  class Base < Vagrant::Command::Base
5
- include Command::Helpers
6
65
 
7
66
  attr_reader :env, :options
8
67
 
9
68
  def initialize(env, options)
10
69
  @env, @options = env, options
70
+ @cookbook_status_already_checked ||= :not_checked
71
+
72
+ unless Command::COMMANDS_WITH_NO_COOKBOOK_CHECK.include? self.class
73
+ begin
74
+ with_target_vms() do |vm|
75
+ if vm.created? && vm.state == :running
76
+ @env.ui.info(cookbook_status, :prefix => false) unless Engineyard::Local.cookbook_version_verified?
77
+ Engineyard::Local.cookbook_version_verified
78
+ else
79
+ cookbook_status(:partial, false)
80
+ end
81
+ end
82
+ rescue Vagrant::Errors::NoEnvironmentError
83
+ # Ignore this error. It will happen any time an ey-local/vagrant command is invoked
84
+ # in a directory that is not yet setup with a Vagrant environment.
85
+ end
86
+ end
87
+
11
88
  end
12
89
  end
13
90
  end
@@ -1,8 +1,21 @@
1
+ require 'engineyard-local/command'
2
+
1
3
  module Engineyard
2
4
  module Local
3
5
  module Command
4
6
  # TODO move to purely vagrant command based setup
5
7
  class Group < Thor
8
+
9
+ def self.printable_tasks(all = true, subcommand = false)
10
+ (all ? all_tasks : tasks).map do |_, task|
11
+ next if task.hidden?
12
+ item = []
13
+ item << banner(task, false, subcommand)
14
+ item << (task.description ? "# #{task.description.gsub(/ +/m,' ')}" : "")
15
+ item
16
+ end.compact
17
+ end
18
+
6
19
  # TODO this class level env crap will go away once
7
20
  # these commands are moved out of thor to Vagrant commands
8
21
  def self.env=(env)
@@ -13,6 +26,25 @@ module Engineyard
13
26
  def env
14
27
  @@env
15
28
  end
29
+
30
+ def externally_register_vm(e)
31
+ eylocal_up_path = File.join(e.home_path,'eylocal-up')
32
+ lines = FileTest.exists?(eylocal_up_path) &&
33
+ FileTest.file?(eylocal_up_path) &&
34
+ FileTest.readable?(eylocal_up_path) ? File.read(eylocal_up_path).split : []
35
+ lines << e.cwd
36
+ File.open(eylocal_up_path, 'w+') {|fh| fh.write lines.join("\n")}
37
+ end
38
+
39
+ def externally_unregister_vm(e)
40
+ eylocal_up_path = File.join(e.home_path,'eylocal-up')
41
+ lines = FileTest.exists?(eylocal_up_path) &&
42
+ FileTest.file?(eylocal_up_path) &&
43
+ FileTest.readable?(eylocal_up_path) ? File.read(eylocal_up_path).split : []
44
+ lines.reject! {|l| l =~ /#{e.cwd}/}
45
+ File.open(eylocal_up_path, 'w+') {|fh| fh.write lines.join("\n")}
46
+ end
47
+
16
48
  end
17
49
 
18
50
  # NOTE this is generally a bad idea as it might break between Vagrant versions
@@ -32,6 +64,14 @@ module Engineyard
32
64
  # register the command group eylocal
33
65
  # register(*command_info[:eylocal])
34
66
 
67
+ map "-h" => :help
68
+ default_task :help
69
+
70
+ desc(*command_info[:help])
71
+ def help(*args)
72
+ Command::Help.new(env, options).exec(self, *args)
73
+ end
74
+
35
75
  # make sure rails is installed, run rails commands in the guest project share
36
76
  method_option "version", :type => :string, :default => nil
37
77
  desc(*command_info[:rails])
@@ -45,12 +85,20 @@ module Engineyard
45
85
  end
46
86
 
47
87
  # streamlining of Vagrant up
48
- method_option "no-bundle", :type => :boolean, :default => nil
49
- method_option "no-db-setup", :type => :boolean, :default => nil
50
- method_option "silent", :type => :boolean, :default => nil
88
+
89
+ method_option "no-chef", :type => :boolean, :default => nil
90
+ method_option "no-dna", :type => :boolean, :default => nil
91
+ method_option "no-bundle", :type => :boolean, :default => nil
92
+ method_option "no-db-setup", :type => :boolean, :default => nil
93
+ method_option "silent", :type => :boolean, :default => nil
51
94
  desc(*command_info[:up])
52
95
  def up(*args)
53
- Command::Up.new(env, options).exec(*args)
96
+ Command::Up.new(env, options).exec(*args) && externally_register_vm(env)
97
+ end
98
+
99
+ desc(*command_info[:down])
100
+ def down(*args)
101
+ Command::VagrantAction.new(env, options).exec(:halt) && externally_unregister_vm(env)
54
102
  end
55
103
 
56
104
  method_option "environment", :type => :string, :default => "development"
@@ -73,13 +121,29 @@ module Engineyard
73
121
 
74
122
  desc(*command_info[:start])
75
123
  def start
76
- Command::VagrantAction.new(env, options).exec(:resume)
124
+ Command::Start.new(env, options).exec()
77
125
  end
78
126
 
79
127
  desc(*command_info[:stop])
80
128
  def stop
81
- Command::VagrantAction.new(env, options).exec(:suspend)
129
+ Command::Stop.new(env, options).exec()
130
+ end
131
+
132
+ desc(*command_info[:status])
133
+ def status(*args)
134
+ Command::Status.new(env, options).exec(env)
82
135
  end
136
+
137
+ desc(*command_info[:update])
138
+ def update(*args)
139
+ Command::Update.new(env, options).exec()
140
+ end
141
+
142
+ desc(*command_info[:terminate])
143
+ def terminate(*args)
144
+ Command::Terminate.new(env, options).exec()
145
+ end
146
+
83
147
  end
84
148
  end
85
149
  end
@@ -0,0 +1,36 @@
1
+ module Engineyard
2
+ module Local
3
+ module Command
4
+ class Help < Base
5
+
6
+ def exec(thor, *args)
7
+ list = Engineyard::Local::Command::Group.printable_tasks
8
+ Thor::Util.thor_classes_in(thor.class).each do |klass|
9
+ list += klass.printable_tasks(false)
10
+ end
11
+
12
+ truncate_output = true
13
+
14
+ if !args.empty?
15
+ list = list.select { |i| args.any? { |a| i.first =~ /^[\w\-]+\s+#{a}\b/ } }
16
+ truncate_output = false
17
+ list.sort!{ |a,b| a[0] <=> b[0] }.each do |h|
18
+ thor.shell.say(h[0], nil, true)
19
+ insert_linebreaks(h[1]).each do |line|
20
+ thor.shell.say("#{' ' * 4}#{line}", nil, true)
21
+ end
22
+ end
23
+ else
24
+ list.sort!{ |a,b| a[0] <=> b[0] }
25
+
26
+ thor.shell.say "Commands:"
27
+ thor.shell.print_table(list, :indent => 2, :truncate => truncate_output)
28
+ thor.shell.say
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,18 @@ module Engineyard
2
2
  module Local
3
3
  module Command
4
4
  module Helpers
5
+
6
+ # Stupid, simple formatter for text. Returns an array of lines.
7
+ def insert_linebreaks(txt, maxlength = 76, ensure_linebreaks = true)
8
+ "#{txt} ".scan(/.{0,#{maxlength}}\s+/).collect do |line|
9
+ if ensure_linebreaks
10
+ line =~ /\n$/ ? line : line + "\n"
11
+ else
12
+ line
13
+ end
14
+ end
15
+ end
16
+
5
17
  def run(middleware, opts={}, &block)
6
18
  with_target_vms do |vm|
7
19
  opts = merge_run_options(vm, opts)
@@ -0,0 +1,26 @@
1
+ module Engineyard
2
+ module Local
3
+ module Command
4
+ class Start < Base
5
+
6
+ # Wrap Vagrant's :resume so that it checks to see if the instance is suspended first, and gives helpful output if it is not.
7
+ def exec(*args)
8
+ with_target_vms do |vm|
9
+ if vm.created?
10
+ if ( vm.state == :saved )
11
+ vm.resume
12
+ elsif ( vm.state == :running )
13
+ env.ui.info( insert_linebreaks( I18n.t( "eylocal.start.running" ) ) )
14
+ else
15
+ env.ui.info( insert_linebreaks( I18n.t( "eylocal.start.not_startable" , :state => vm.state ) ) )
16
+ end
17
+ else
18
+ env.ui.info( I18n.t( "eylocal.start.not_created" ) )
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require 'optparse'
2
+ require 'nokogiri'
3
+
4
+ module Engineyard
5
+ module Local
6
+ module Command
7
+ class Status < Base
8
+
9
+ def exec(*args)
10
+ state = nil
11
+ results = []
12
+
13
+ cb_status = nil
14
+
15
+ with_target_vms do |vm|
16
+ cb_status = cookbook_status(:full) if vm.state == :running
17
+
18
+ state = vm.state.to_s if !state
19
+ results << "#{vm.name.to_s.ljust(25)}#{vm.state.to_s.gsub("_", " ")}"
20
+ end
21
+
22
+ state = results.length == 1 ? state : "listing"
23
+
24
+ @env.ui.info(I18n.t("vagrant.commands.status.output",
25
+ :states => results.join("\n"),
26
+ :message => I18n.t("vagrant.commands.status.#{state}"),
27
+ :alerts => insert_linebreaks( cb_status ).join ),
28
+ :prefix => false)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ module Engineyard
2
+ module Local
3
+ module Command
4
+ class Stop < Base
5
+
6
+ # Wrap Vagrant's :resume so that it checks to see if the instance is suspended first, and gives helpful output if it is not.
7
+ def exec(*args)
8
+ with_target_vms do |vm|
9
+ if vm.created?
10
+ if ( vm.state == :running )
11
+ vm.suspend
12
+ elsif ( vm.state == :saved )
13
+ env.ui.info( insert_linebreaks( I18n.t( "eylocal.stop.saved" ) ) )
14
+ else
15
+ env.ui.info( insert_linebreaks( I18n.t( "eylocal.stop.not_stoppable" , :state => vm.state ) ) )
16
+ end
17
+ else
18
+ env.ui.info( I18n.t( "eylocal.stop.not_created" ) )
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module Engineyard
2
+ module Local
3
+ module Command
4
+ class Terminate < Base
5
+
6
+ # Wrap Vagrant's :destroy
7
+ def exec(*args)
8
+ with_target_vms do |vm|
9
+ if vm.created?
10
+ env.ui.info( I18n.t( "eylocal.terminate.destroying" ) )
11
+ vm.destroy
12
+ File.unlink(cached_data_path) if FileTest.exist? cached_data_path
13
+ else
14
+ env.ui.info( I18n.t( "eylocal.terminate.not_created" ) )
15
+ end
16
+ end
17
+ end
18
+
19
+ def cached_data_path
20
+ "#{@env.root_path}/.ey_local_data"
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -2,6 +2,19 @@ module Engineyard
2
2
  module Local
3
3
  module Command
4
4
  class Up < Base
5
+
6
+ # install the application bundle and create/migrate the database
7
+ # TODO check for the database.yml and fail gracefully
8
+ def self.setup_stack(options)
9
+ Vagrant::Action::Builder.new do
10
+ use Middleware::DNA unless options["no-dna"]
11
+ use Middleware::Chef unless options["no-chef"]
12
+ use Middleware::Bundle unless options["no-bundle"]
13
+ use Middleware::Rails::DB unless options["no-db-setup"]
14
+ use Middleware::Rails::Assets
15
+ end
16
+ end
17
+
5
18
  def box_defaults
6
19
  Local.config[:box_defaults]
7
20
  end
@@ -31,17 +44,20 @@ module Engineyard
31
44
  env.boxes.reload!
32
45
 
33
46
  env.ui.info(I18n.t("eylocal.up.root_path", :root_path => env.root_path))
34
- if File.expand_path(env.root_path) != File.expand_path(Dir.pwd)
35
- env.ui.info(I18n.t("eylocal.up.root_path_instructions", :root_path => env.root_path, :pwd => Dir.pwd))
47
+ if !pwd_matches_root_path
48
+ env.ui.info(I18n.t("eylocal.up.root_path_instructions",
49
+ :root_path => env.root_path, :pwd => Dir.pwd))
36
50
  end
37
51
 
38
52
  # don't build a box if its already built
39
53
  with_target_vms do |vm|
40
54
  if vm.created?
41
55
  env.ui.info I18n.t("vagrant.commands.up.vm_created")
56
+ if ! ( vm.state == 'running' )
57
+ vm.start
58
+ end
42
59
  else
43
60
  up = Vagrant.actions.get(:up)
44
-
45
61
  # insert the tag before the box is in a state where it can't be saved eg running
46
62
  up.insert_before(Vagrant::Action::VM::CheckGuestAdditions, Middleware::Tag)
47
63
  up.insert_before(Vagrant::Action::VM::CheckGuestAdditions, Middleware::Network, @options)
@@ -52,11 +68,15 @@ module Engineyard
52
68
  end
53
69
 
54
70
  # finish the box setup
55
- run setup_stack(options)
71
+ run self.class.setup_stack(options)
56
72
  end
57
73
 
58
74
  private
59
75
 
76
+ def pwd_matches_root_path
77
+ File.expand_path(env.root_path) == File.expand_path(Dir.pwd)
78
+ end
79
+
60
80
  # prefer the the base box included with the installer if it exists
61
81
  # otherwise use the default downloadable box
62
82
  def box_uri
@@ -70,17 +90,6 @@ module Engineyard
70
90
  box_defaults[:uri]
71
91
  end
72
92
  end
73
-
74
- # install the application bundle and create/migrate the database
75
- # TODO check for the database.yml and fail gracefully
76
- def setup_stack(options)
77
- Vagrant::Action::Builder.new do
78
- use Middleware::DNA unless options["no-dna"]
79
- use Middleware::Chef unless options["no-chef"]
80
- use Middleware::Bundle unless options["no-bundle"]
81
- use Middleware::Rails::DB unless options["no-db-setup"]
82
- end
83
- end
84
93
  end
85
94
  end
86
95
  end