engineyard-local 0.2.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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