machines 0.5.4 → 0.5.6

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 (93) hide show
  1. data/.yardopts +7 -1
  2. data/CHANGELOG.md +16 -4
  3. data/INSTALL.md +3 -0
  4. data/LICENSE +1 -2
  5. data/README.md +47 -28
  6. data/Rakefile +0 -8
  7. data/TODO.md +66 -59
  8. data/bin/machines +1 -2
  9. data/lib/machines.rb +16 -1
  10. data/lib/machines/app_settings.rb +1 -1
  11. data/lib/machines/cloud_machine.rb +1 -1
  12. data/lib/machines/command.rb +0 -2
  13. data/lib/machines/commandline.rb +23 -29
  14. data/lib/machines/commands/checks.rb +67 -0
  15. data/lib/machines/commands/configuration.rb +50 -0
  16. data/lib/machines/commands/database.rb +18 -0
  17. data/lib/machines/commands/file_operations.rb +105 -0
  18. data/lib/machines/commands/installation.rb +184 -0
  19. data/lib/machines/commands/questions.rb +16 -0
  20. data/lib/machines/commands/services.rb +26 -0
  21. data/lib/machines/core.rb +55 -25
  22. data/lib/machines/logger.rb +0 -2
  23. data/lib/machines/named_buffer.rb +7 -6
  24. data/lib/machines/version.rb +1 -1
  25. data/lib/packages/awstats.rb +2 -2
  26. data/lib/packages/docky.rb +0 -1
  27. data/lib/packages/dwm.rb +5 -0
  28. data/lib/packages/nginx_logrotate.rb +2 -2
  29. data/lib/packages/timezone.rb +2 -4
  30. data/lib/template/Machinesfile +2 -1
  31. data/lib/template/config.yml +3 -0
  32. data/spec/lib/machines/app_settings_spec.rb +13 -12
  33. data/spec/lib/machines/cloud_machine_spec.rb +9 -8
  34. data/spec/lib/machines/commandline_spec.rb +69 -90
  35. data/spec/lib/machines/{checks_spec.rb → commands/checks_spec.rb} +1 -1
  36. data/spec/lib/machines/{configuration_spec.rb → commands/configuration_spec.rb} +2 -3
  37. data/spec/lib/machines/{database_spec.rb → commands/database_spec.rb} +4 -10
  38. data/spec/lib/machines/{file_operations_spec.rb → commands/file_operations_spec.rb} +3 -7
  39. data/spec/lib/machines/{installation_spec.rb → commands/installation_spec.rb} +10 -4
  40. data/spec/lib/machines/{questions_spec.rb → commands/questions_spec.rb} +1 -3
  41. data/spec/lib/machines/{services_spec.rb → commands/services_spec.rb} +1 -4
  42. data/spec/lib/machines/core_spec.rb +81 -65
  43. data/spec/lib/packages/abiword_spec.rb +1 -5
  44. data/spec/lib/packages/amazon_mp3_spec.rb +0 -4
  45. data/spec/lib/packages/awstats_spec.rb +3 -4
  46. data/spec/lib/packages/base_spec.rb +0 -1
  47. data/spec/lib/packages/chrome_spec.rb +0 -4
  48. data/spec/lib/packages/cruisecontrol_spec.rb +1 -2
  49. data/spec/lib/packages/dependencies_spec.rb +1 -2
  50. data/spec/lib/packages/docky_spec.rb +0 -4
  51. data/spec/lib/packages/dotfiles_spec.rb +5 -4
  52. data/spec/lib/packages/dwm_spec.rb +23 -0
  53. data/spec/lib/packages/file_roller_spec.rb +1 -5
  54. data/spec/lib/packages/firefox_spec.rb +0 -4
  55. data/spec/lib/packages/gedit_spec.rb +1 -5
  56. data/spec/lib/packages/git_spec.rb +0 -4
  57. data/spec/lib/packages/gmate_spec.rb +1 -5
  58. data/spec/lib/packages/gnome_spec.rb +0 -4
  59. data/spec/lib/packages/gnumeric_spec.rb +1 -5
  60. data/spec/lib/packages/hosts_spec.rb +0 -1
  61. data/spec/lib/packages/load_machines_spec.rb +16 -15
  62. data/spec/lib/packages/monit_spec.rb +0 -1
  63. data/spec/lib/packages/mysql_spec.rb +1 -3
  64. data/spec/lib/packages/nginx_logrotate_spec.rb +17 -18
  65. data/spec/lib/packages/nginx_spec.rb +0 -1
  66. data/spec/lib/packages/openbox_spec.rb +0 -4
  67. data/spec/lib/packages/passenger_nginx_spec.rb +0 -1
  68. data/spec/lib/packages/passenger_spec.rb +0 -1
  69. data/spec/lib/packages/postfix_spec.rb +1 -5
  70. data/spec/lib/packages/questions_spec.rb +3 -4
  71. data/spec/lib/packages/rbenv_spec.rb +1 -4
  72. data/spec/lib/packages/rvm_spec.rb +1 -4
  73. data/spec/lib/packages/save_machines_spec.rb +0 -1
  74. data/spec/lib/packages/slim_spec.rb +1 -2
  75. data/spec/lib/packages/sqlserver_spec.rb +0 -4
  76. data/spec/lib/packages/timezone_spec.rb +2 -3
  77. data/spec/lib/packages/unison_spec.rb +1 -2
  78. data/spec/lib/packages/virtualbox_guest_spec.rb +0 -4
  79. data/spec/lib/packages/virtualbox_spec.rb +1 -2
  80. data/spec/lib/packages/webapps_spec.rb +1 -3
  81. data/spec/spec_helper.rb +59 -61
  82. data/spec/support/minitest.rb +4 -62
  83. metadata +27 -28
  84. data/lib/machines/base.rb +0 -13
  85. data/lib/machines/checks.rb +0 -63
  86. data/lib/machines/configuration.rb +0 -49
  87. data/lib/machines/database.rb +0 -17
  88. data/lib/machines/file_operations.rb +0 -104
  89. data/lib/machines/installation.rb +0 -171
  90. data/lib/machines/machinesfile.rb +0 -25
  91. data/lib/machines/questions.rb +0 -15
  92. data/lib/machines/services.rb +0 -24
  93. data/spec/lib/machines/machinesfile_spec.rb +0 -34
@@ -0,0 +1,16 @@
1
+ module Machines
2
+ module Commands
3
+ module Questions
4
+ def enter_password(type, confirm = true)
5
+ begin
6
+ password = ask("Enter #{type} password: ") { |question| question.echo = false }
7
+ break unless confirm
8
+ password_confirmation = ask('Confirm the password: ') { |question| question.echo = false }
9
+ say "Passwords do not match, please re-enter" unless password == password_confirmation
10
+ end while password != password_confirmation
11
+ $conf.passwords << password if $conf.passwords && password.size > 4 && password != 'password'
12
+ password
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module Machines
2
+ module Commands
3
+ module Services
4
+ # Stop a daemon
5
+ # @param [String] daemon Name of the service to stop
6
+ def stop daemon
7
+ Command.new("service #{daemon} stop", check_daemon(daemon, false))
8
+ end
9
+
10
+ # Start a daemon
11
+ # @param [String] daemon Name of the service to start
12
+ # @param [Hash] options
13
+ # @option options [Boolean] :check Set to false to disable the check (e.g. start hostname, :check => false)
14
+ def start daemon, options = {}
15
+ check = options[:check] || check_daemon(daemon)
16
+ Command.new("service #{daemon} start", check)
17
+ end
18
+
19
+ # Restart a daemon
20
+ # @param [String] daemon Name of the service to restart
21
+ def restart daemon
22
+ Command.new("service #{daemon} restart", check_daemon(daemon))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,13 @@
1
1
  module Machines
2
- module Core
2
+ class Core
3
+ include Commands::Checks
4
+ include Commands::Configuration
5
+ include Commands::Database
6
+ include Commands::FileOperations
7
+ include Commands::Installation
8
+ include Commands::Questions
9
+ include Commands::Services
10
+
3
11
  # If a block is given, store the task, log it and run it
4
12
  # If no block is given, sets commands to only those of the specified tasks so they can be run standalone
5
13
  # @param [Symbol, String, Array] name Name of the task or array of task names
@@ -26,12 +34,6 @@ module Machines
26
34
  $conf.tasks[name] = {:description => description, :block => block}
27
35
  end
28
36
 
29
- def list_tasks
30
- $conf.tasks.each do |name, task|
31
- say " #{"%-20s" % name}#{task[:description]}"
32
- end
33
- end
34
-
35
37
  def generate_password
36
38
  WEBrick::Utils.random_string(20)
37
39
  end
@@ -46,25 +48,22 @@ module Machines
46
48
  yield unless matched(options)
47
49
  end
48
50
 
49
- def matched options
50
- options.each do |key, value|
51
- value = value.is_a?(Array) ? value.map{|o| o.to_s } : value.to_s
52
- if $conf[key].is_a?(Array)
53
- values = $conf[key].map{|o| o.to_s }
54
- if value.is_a?(Array)
55
- return unless values.reject{ |symbol| !value.include?(symbol.to_s) }.any?
56
- else
57
- return unless values.include?(value)
58
- end
59
- else
60
- if value.is_a?(Array)
61
- return unless value.include?($conf[key].to_s)
62
- else
63
- return unless value == $conf[key].to_s
64
- end
65
- end
51
+ def load_app_settings(apps)
52
+ AppSettings.new.load_app_settings(apps)
53
+ end
54
+
55
+ # Loads the Machinesfile or a package
56
+ def package name
57
+ if name == 'Machinesfile'
58
+ custom_name = builtin_name = 'Machinesfile'
59
+ error = "Cannot find 'Machinesfile'. Use `machines new` to create a template."
60
+ else
61
+ custom_name = File.join('packages', "#{name}.rb")
62
+ builtin_name = File.join($conf.application_dir, 'packages', "#{name}.rb")
63
+ error = "Cannot find custom or built-in package '#{name}'."
66
64
  end
67
- true
65
+ package = load_and_eval(custom_name) || load_and_eval(builtin_name)
66
+ package || raise(LoadError, error, caller)
68
67
  end
69
68
 
70
69
  # Queue up command(s) to run remotely
@@ -112,9 +111,40 @@ module Machines
112
111
  end
113
112
  end
114
113
 
114
+ #TODO: Move matched into separate class to test
115
+ def matched options
116
+ options.each do |key, value|
117
+ value = value.is_a?(Array) ? value.map{|o| o.to_s } : value.to_s
118
+ if $conf[key].is_a?(Array)
119
+ values = $conf[key].map{|o| o.to_s }
120
+ if value.is_a?(Array)
121
+ return unless values.reject{ |symbol| !value.include?(symbol.to_s) }.any?
122
+ else
123
+ return unless values.include?(value)
124
+ end
125
+ else
126
+ if value.is_a?(Array)
127
+ return unless value.include?($conf[key].to_s)
128
+ else
129
+ return unless value == $conf[key].to_s
130
+ end
131
+ end
132
+ end
133
+ true
134
+ end
135
+
136
+ private
137
+ def load_and_eval package_name
138
+ if File.exists?(package_name)
139
+ eval(File.read(package_name), nil, "eval: #{package_name}")
140
+ true
141
+ end
142
+ end
143
+
115
144
  def command_from_string commands
116
145
  commands.first.is_a?(String) ? [Command.new(commands[0], commands[1])] : commands
117
146
  end
147
+
118
148
  end
119
149
  end
120
150
 
@@ -1,5 +1,3 @@
1
- require 'date'
2
-
3
1
  module Machines
4
2
  class Logger
5
3
  HighLine.color_scheme = HighLine::ColorScheme.new do |cs|
@@ -1,9 +1,10 @@
1
- class NamedBuffer < StringIO
2
- attr_reader :name
1
+ module Machines
2
+ class NamedBuffer < StringIO
3
+ attr_reader :name
3
4
 
4
- def initialize name, string
5
- super string
6
- @name = name
5
+ def initialize name, string
6
+ super string
7
+ @name = name
8
+ end
7
9
  end
8
10
  end
9
-
@@ -1,4 +1,4 @@
1
1
  module Machines
2
- VERSION = '0.5.4'
2
+ VERSION = '0.5.6'
3
3
  end
4
4
 
@@ -4,7 +4,7 @@ task :awstats, 'Install AWStats' do
4
4
  local_file = '/usr/local/bin/awstats_render'
5
5
  sudo "wget #{remote_file} -O #{local_file}", check_file(local_file)
6
6
  sudo chmod '+x', local_file
7
-
7
+
8
8
  $conf.webapps.each do |app_name, app|
9
9
  stats_path = "/etc/awstats/awstats.#{app.server_name}.conf"
10
10
  sudo create_from 'misc/awstats.conf.erb', settings: app, to: stats_path
@@ -13,4 +13,4 @@ task :awstats, 'Install AWStats' do
13
13
  run mkdir "#{app_stats}/public"
14
14
  end
15
15
  end
16
-
16
+
@@ -33,4 +33,3 @@ task :docky, 'Install and configure Docky a dock and app launcher' do
33
33
  run configure '/apps/docky-2/WeatherDocklet/WeatherPreferences/Location' => ['London\\, United Kingdom']
34
34
  run configure '/apps/docky-2/WeatherDocklet/WeatherPreferences/Metric' => true
35
35
  end
36
-
@@ -0,0 +1,5 @@
1
+ task :dwm, 'Download, compile and install dwm' do
2
+ sudo install %w(build-essential libx11-dev libxinerama-dev sharutils)
3
+
4
+ sudo install "http://dl.suckless.org/dwm/dwm-#{$conf.dwm.version}.tar.gz", make: true
5
+ end
@@ -7,7 +7,7 @@ task :logrotate_nginx, 'Logrotate nginx access and error logs and optionally gen
7
7
  else
8
8
  stats_prerotate = stats_postrotate = nil
9
9
  end
10
- settings = Machines::AppSettings::AppBuilder.new(
10
+ settings = AppSettings::AppBuilder.new(
11
11
  log_path: "/var/log/nginx/#{app.name}.#{type}.log",
12
12
  stats_prerotate: stats_prerotate,
13
13
  stats_postrotate: stats_postrotate
@@ -19,7 +19,7 @@ end
19
19
 
20
20
  task :logrotate_apps, 'Logrotate Rails app logs' do
21
21
  $conf.webapps.each do |app_name, app|
22
- settings = Machines::AppSettings::AppBuilder.new(log_path: File.join(app.path, 'shared', 'log', '*.log'))
22
+ settings = AppSettings::AppBuilder.new(log_path: File.join(app.path, 'shared', 'log', '*.log'))
23
23
  sudo create_from 'logrotate/app.erb', settings: settings, to: File.join('/etc', 'logrotate.d', "#{app.name}_app")
24
24
  end
25
25
  end
@@ -1,10 +1,8 @@
1
1
  task :timezone, 'Set timezone from config.yml' do
2
- sudo link '/etc/localtime', "/usr/share/zoneinfo/#{$conf.timezone}"
3
-
4
- # Ensure UTC is used or not
2
+ sudo link "/usr/share/zoneinfo/#{$conf.timezone}", '/etc/localtime'
3
+ # Ensure UTC is configured
5
4
  if !$conf.clock_utc.nil?
6
5
  options = {false => 'no', true => 'yes'}
7
6
  sudo replace "UTC=#{options[!$conf.clock_utc]}", :with => "UTC=#{options[$conf.clock_utc]}", :in => '/etc/default/rcS'
8
7
  end
9
8
  end
10
-
@@ -30,7 +30,8 @@ end
30
30
 
31
31
  only :user => 'phil' do
32
32
  package :sudo_mods
33
- package :subtle
33
+ package :slim
34
+ package :dwm
34
35
  package :chrome
35
36
  package :firefox
36
37
  package :gedit
@@ -23,6 +23,9 @@ cloud:
23
23
  aws_access_key_id: 123
24
24
  aws_secret_access_key: 456
25
25
 
26
+ dwm:
27
+ version: 6.0
28
+
26
29
  # IP hosts. These are added to /etc/hosts by the hosts task in the base package
27
30
  # They are also added to known hosts but the host must be accessible at this point
28
31
  # Note:
@@ -1,13 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'AppSettings' do
4
- include Machines::AppSettings
3
+ describe AppSettings do
4
+
5
+ subject { AppSettings.new }
5
6
 
6
7
  describe 'load_and_generate_passwords_for_webapps' do
7
8
  it 'generates passwords and saves to webapps.yml' do
8
9
  File.open('webapps.yml', 'w') {|f| f.puts "###\n\n---\nwebapps:\n my_app:\n development:\n password: \n" }
9
- stubs(:generate_password).returns 'random'
10
- load_and_generate_passwords_for_webapps
10
+ subject.stubs(:generate_password).returns 'random'
11
+ subject.load_and_generate_passwords_for_webapps
11
12
  File.read('webapps.yml').must_equal "###\n\n---\nwebapps:\n my_app:\n development:\n password: random\n"
12
13
  end
13
14
  end
@@ -30,9 +31,9 @@ EOF
30
31
  end
31
32
 
32
33
  it 'loads the app settings for selected apps' do
33
- load_app_settings ['app']
34
+ subject.load_app_settings ['app']
34
35
  $conf.webapps.must_equal({
35
- 'app' => AppBuilder.new(
36
+ 'app' => AppSettings::AppBuilder.new(
36
37
  :scm => 'scm://project.git',
37
38
  :name => 'app',
38
39
  :path => '/home/user/app',
@@ -45,9 +46,9 @@ EOF
45
46
 
46
47
  it 'handles ssl settings' do
47
48
  File.open('webapps.yml', 'w') {|f| f.puts @settings }
48
- load_app_settings ['app']
49
+ subject.load_app_settings ['app']
49
50
  $conf.webapps.must_equal({
50
- 'app' => AppBuilder.new(
51
+ 'app' => AppSettings::AppBuilder.new(
51
52
  :name => 'app',
52
53
  :scm => 'scm://project.git',
53
54
  :path => '/home/user/app',
@@ -64,7 +65,7 @@ EOF
64
65
 
65
66
  it 'does not fail when settings not included for specified environment' do
66
67
  File.open('webapps.yml', 'w') {|f| f.puts "---\nwebapps:\n app:\n path: path\n" }
67
- load_app_settings(['app'])
68
+ subject.load_app_settings(['app'])
68
69
  end
69
70
 
70
71
  it 'loads settings for all apps when none specified' do
@@ -83,16 +84,16 @@ webapps:
83
84
  password: secure
84
85
  EOF
85
86
  File.open('webapps.yml', 'w') {|f| f.puts settings }
86
- load_app_settings nil
87
+ subject.load_app_settings nil
87
88
  $conf.webapps.must_equal({
88
- 'app' => AppBuilder.new(
89
+ 'app' => AppSettings::AppBuilder.new(
89
90
  :name => 'app',
90
91
  :path => '/home/user/app',
91
92
  :scm => 'scm://project.git',
92
93
  :root => '/home/user/app/current/public',
93
94
  :setting => 'setting',
94
95
  :password => 'secure'),
95
- 'other' => AppBuilder.new(
96
+ 'other' => AppSettings::AppBuilder.new(
96
97
  :name => 'other',
97
98
  :root => '/home/user/other/current/public',
98
99
  :scm => 'scm://other_project',
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'fog'
3
3
 
4
- describe 'CloudMachine' do
5
- include Machines::CloudMachine
4
+ describe CloudMachine do
5
+
6
+ subject { CloudMachine.new }
6
7
 
7
8
  before do
8
9
  Fog.mock!
@@ -11,11 +12,11 @@ describe 'CloudMachine' do
11
12
  end
12
13
 
13
14
  it 'displays an error message when fog gem is not available' do
14
- stubs(:require)
15
- expects(:require).with('fog').raises LoadError
15
+ subject.stubs(:require)
16
+ subject.expects(:require).with('fog').raises LoadError
16
17
  lambda do
17
18
  begin
18
- connect_to_cloud
19
+ subject.connect_to_cloud
19
20
  rescue LoadError
20
21
  end
21
22
  end.must_output "fog gem required to use cloud features.
@@ -24,13 +25,13 @@ Please \"gem install fog\".
24
25
  end
25
26
 
26
27
  it 'sets correct options and connects' do
27
- connect_to_cloud
28
+ subject.connect_to_cloud
28
29
  $conf.cloud.connection.must_be_kind_of Fog::Compute::AWS::Mock
29
30
  end
30
31
 
31
32
  it 'creates a server' do
32
- connect_to_cloud
33
- create_server
33
+ subject.connect_to_cloud
34
+ subject.create_server
34
35
  end
35
36
  end
36
37
 
@@ -1,11 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Machines::Commandline do
4
- include Machines::Core
5
- include Machines::Commandline
6
- include Machines::Questions
3
+ describe Commandline do
4
+
5
+ subject { Commandline.new }
7
6
 
8
7
  before(:each) do
8
+ subject
9
+ Commandline.stubs(:new).returns subject
9
10
  $conf.log_only = false
10
11
  File.open('config.yml', 'w') {|f| f.puts "timezone: GB" }
11
12
  FileUtils.mkdir_p 'log'
@@ -13,7 +14,7 @@ describe Machines::Commandline do
13
14
 
14
15
  describe 'build' do
15
16
  before(:each) do
16
- stubs(:init)
17
+ subject.stubs(:init)
17
18
  FileUtils.touch('Machinesfile')
18
19
  $conf.machine = AppConf.new
19
20
  $conf.machine.address = 'target'
@@ -25,18 +26,18 @@ describe Machines::Commandline do
25
26
  end
26
27
 
27
28
  it 'displays syntax when no machine name specified' do
28
- lambda { build [] }.must_output Machines::Help.new.syntax
29
+ lambda { subject.build [] }.must_output Help.new.syntax
29
30
  end
30
31
 
31
32
  it 'sets machine_name' do
32
- build ['machine']
33
+ subject.build ['machine']
33
34
  $conf.machine_name.must_equal 'machine'
34
35
  end
35
36
 
36
37
  it 'starts an SCP session using password authentication' do
37
38
  options = {paranoid: false, password: 'userpass'}
38
39
  Net::SSH.expects(:start).with('target', 'username', options).returns @ssh_stub
39
- build ['machine']
40
+ subject.build ['machine']
40
41
  end
41
42
 
42
43
  it 'starts an SCP session using key based authentication' do
@@ -46,52 +47,53 @@ describe Machines::Commandline do
46
47
  options = {paranoid: false, keys: ['path/to/private_key']}
47
48
  Net::SSH.expects(:start).with('target', 'ubuntu', options).returns @ssh_stub
48
49
 
49
- build ['machine']
50
+ subject.build ['machine']
50
51
  end
51
52
 
52
53
  it 'runs each command' do
53
- mock_command = mock 'Machines::Command'
54
+ mock_command = mock 'Command'
54
55
  $conf.commands = [mock_command]
55
56
 
56
57
  mock_command.expects(:run)
57
58
 
58
- build ['machine']
59
+ subject.build ['machine']
59
60
  end
60
61
 
61
62
  it 'flushes log file after running command' do
62
63
  $conf.log_only = false
63
- command_stub = stub('Machines::Command', :run => nil)
64
+ command_stub = stub('command', :run => nil)
64
65
  $conf.commands = [command_stub]
65
66
 
66
- Machines::Command.file.expects(:flush)
67
- build ['machine']
67
+ Command.file.expects(:flush)
68
+ subject.build ['machine']
68
69
  end
69
70
 
70
71
  it 'only run specified tasks' do
71
- command_will_run = Machines::Command.new '', ''
72
- command_also_run = Machines::Command.new '', ''
73
- command_wont_run = Machines::Command.new '', ''
74
- $conf.tasks = {
75
- :task1 => {:block => Proc.new { run command_will_run }},
76
- :task2 => {:block => Proc.new { run command_also_run }}
72
+ command_will_run = Command.new 'will run', ''
73
+ command_also_run = Command.new 'also run', ''
74
+ command_wont_run = Command.new 'wont run', ''
75
+ $conf.tasks = {
76
+ :task1 => {:block => lambda { $conf.commands << command_will_run }},
77
+ :task2 => {:block => lambda { $conf.commands << command_also_run }},
78
+ :task3 => {:block => lambda { $conf.commands << command_wont_run }}
77
79
  }
78
80
 
79
- build ['machine', 'task1', 'task2']
81
+ subject.build ['machine', 'task1', 'task2']
80
82
 
81
83
  $conf.commands.must_equal [command_will_run, command_also_run]
82
84
  end
83
85
 
84
86
  it 'logs instead of SSHing and running commands' do
85
87
  Net::SCP.expects(:start).never
86
- $conf.commands = [mock('Machines::Command')]
88
+ $conf.commands = [mock('command')]
87
89
  $conf.commands.first.expects(:run)
88
90
  $conf.log_only = true
89
- build ['machine']
91
+ subject.build ['machine']
90
92
  end
91
93
 
92
94
  describe 'interrupts' do
93
95
  before(:each) do
94
- mock_command = mock 'Machines::Command'
96
+ mock_command = mock 'command'
95
97
  $conf.commands = [mock_command]
96
98
 
97
99
  mock_command.stubs(:run)
@@ -99,14 +101,13 @@ describe Machines::Commandline do
99
101
  end
100
102
 
101
103
  it 'handles CTRL+C and calls handler' do
102
- expects(:prepare_to_exit)
104
+ subject.expects(:prepare_to_exit)
103
105
  Kernel.expects(:trap).with('INT').yields
104
- build ['machine']
106
+ subject.build ['machine']
105
107
  end
106
108
 
107
-
108
109
  it 'sets exit flag and displays message' do
109
- prepare_to_exit
110
+ subject.send :prepare_to_exit
110
111
  $exit_requested.must_equal true
111
112
  message = "\nEXITING after current command completes...\n"
112
113
  $console.next.must_equal colored(message, :warning)
@@ -114,15 +115,15 @@ describe Machines::Commandline do
114
115
 
115
116
  it 'second request to exit exits immediately' do
116
117
  $exit_requested = true
117
- expects(:exit)
118
- prepare_to_exit
118
+ subject.expects(:exit)
119
+ subject.send :prepare_to_exit
119
120
  end
120
121
 
121
122
  it 'exits when exit requested' do
122
123
  $exit_requested = true
123
- expects(:exit)
124
+ subject.expects(:exit)
124
125
 
125
- build ['machine']
126
+ subject.build ['machine']
126
127
  end
127
128
  end
128
129
  end
@@ -130,54 +131,54 @@ describe Machines::Commandline do
130
131
  describe 'dryrun' do
131
132
  it 'asks build to only log commands' do
132
133
  options = []
133
- expects(:build).with options
134
- dryrun options
134
+ subject.expects(:build).with options
135
+ subject.dryrun options
135
136
  $conf.log_only.must_equal true
136
137
  end
137
138
 
138
139
  it 'passes tasks to build' do
139
140
  options = ['machine', 'task']
140
- expects(:build).with options
141
- dryrun options
141
+ subject.expects(:build).with options
142
+ subject.dryrun options
142
143
  end
143
144
  end
144
145
 
145
146
  describe 'execute' do
146
147
  it 'calls specified action' do
147
- Machines::Help.new.actions.reject{|a| a == 'new'}.each do |action|
148
- expects action
149
- execute [action]
148
+ Help.new.actions.reject{|a| a == 'new'}.each do |action|
149
+ subject.expects action
150
+ Commandline.execute [action]
150
151
  end
151
152
  end
152
153
 
153
154
  it 'calls generate with folder' do
154
- expects(:generate).with(['dir'])
155
- execute ['new', 'dir']
155
+ subject.expects(:generate).with(['dir'])
156
+ Commandline.execute ['new', 'dir']
156
157
  end
157
158
 
158
159
  it 'calls generate without folder' do
159
- expects(:generate).with([])
160
- execute ['new']
160
+ subject.expects(:generate).with([])
161
+ Commandline.execute ['new']
161
162
  end
162
163
 
163
164
  it 'calls help when no matching command' do
164
- lambda { execute ['anything'] }.must_output Machines::Help.new.syntax
165
+ lambda { Commandline.execute ['anything'] }.must_output Help.new.syntax
165
166
  end
166
167
  end
167
168
 
168
169
  describe 'generate' do
169
170
  it 'copies the template within ./' do
170
- expects(:ask).with("Overwrite './' (y/n)? ").returns 'y'
171
+ subject.expects(:ask).with("Overwrite './' (y/n)? ").returns 'y'
171
172
  FileUtils.expects(:cp_r).with("#{$conf.application_dir}/template/.", './')
172
173
  FileUtils.expects(:mkdir_p).with('./packages')
173
- generate []
174
+ subject.generate []
174
175
  end
175
176
 
176
177
  it 'copies the template within dir' do
177
178
  FileUtils.expects(:cp_r).with("#{$conf.application_dir}/template/.", 'dir')
178
179
  FileUtils.expects(:mkdir_p).with(File.join('dir', 'packages'))
179
- expects(:say).with('Project created at dir/')
180
- generate ['dir']
180
+ subject.expects(:say).with('Project created at dir/')
181
+ subject.generate ['dir']
181
182
  end
182
183
 
183
184
  describe 'when folder exists' do
@@ -186,17 +187,17 @@ describe Machines::Commandline do
186
187
  end
187
188
 
188
189
  it 'is overwritten after user confirmation' do
189
- expects(:ask).with("Overwrite 'dir' (y/n)? ").returns 'y'
190
+ subject.expects(:ask).with("Overwrite 'dir' (y/n)? ").returns 'y'
190
191
  FileUtils.expects(:cp_r).with("#{$conf.application_dir}/template/.", 'dir')
191
192
  FileUtils.expects(:mkdir_p).with(File.join('dir', 'packages'))
192
- generate ['dir']
193
+ subject.generate ['dir']
193
194
  end
194
195
 
195
196
  it 'generation is aborted at user request' do
196
- expects(:ask).with("Overwrite 'dir' (y/n)? ").returns 'n'
197
+ subject.expects(:ask).with("Overwrite 'dir' (y/n)? ").returns 'n'
197
198
  FileUtils.expects(:cp_r).never
198
199
  FileUtils.expects(:mkdir_p).never
199
- generate ['dir']
200
+ subject.generate ['dir']
200
201
  end
201
202
  end
202
203
  end
@@ -205,54 +206,32 @@ describe Machines::Commandline do
205
206
  it 'htpasswd is generated and saved' do
206
207
  $conf.webserver = 'server'
207
208
  $input.string = "user\npass\npass\n"
208
- htpasswd nil
209
+ subject.htpasswd nil
209
210
  File.read('server/htpasswd').must_match /user:.{13}/
210
211
  end
211
212
  end
212
213
 
213
214
  describe 'init' do
214
215
  it 'initializes some $conf settings and loads configs' do
215
- Machines::Command.file = nil
216
- Machines::Command.console = nil
217
- Machines::Command.debug = nil
218
- init
216
+ Command.file = nil
217
+ Command.console = nil
218
+ Command.debug = nil
219
+ subject.init
219
220
  $conf.passwords.must_equal []
220
221
  $conf.commands.must_equal []
221
222
  $conf.tasks.must_equal({})
222
223
  $conf.timezone.must_equal 'GB'
223
224
  File.exists?('log/output.log').must_equal true
224
- Machines::Command.file.must_be_instance_of Machines::Logger
225
- Machines::Command.console.must_be_instance_of Machines::Logger
226
- Machines::Command.debug.must_be_instance_of Machines::Logger
225
+ Command.file.must_be_instance_of Machines::Logger
226
+ Command.console.must_be_instance_of Machines::Logger
227
+ Command.debug.must_be_instance_of Machines::Logger
227
228
  end
228
229
  end
229
230
 
230
231
  describe 'list' do
231
232
  it 'lists machines' do
232
233
  File.open('machines.yml', 'w') {|f| f.puts({'machines' => {'machine_1' => {}, 'machine_2' => {}}}.to_yaml) }
233
- lambda { list nil }.must_output "Machines from machines.yml:\n machine_1\n machine_2\n"
234
- end
235
- end
236
-
237
- describe 'load_machinesfile' do
238
- it 'raises LoadError with custom message when no Machinesfile' do
239
- File.expects(:read).with("Machinesfile").raises LoadError.new('Machinesfile not found')
240
-
241
- begin
242
- load_machinesfile
243
- rescue LoadError => e
244
- e.message.must_equal 'Machinesfile does not exist. Use `machines new <DIR>` to create a template.'
245
- end
246
- end
247
-
248
- it 'raises normal LoadError on other files' do
249
- File.expects(:read).with("Machinesfile").raises LoadError
250
-
251
- begin
252
- load_machinesfile
253
- rescue LoadError => e
254
- e.message.must_equal 'LoadError'
255
- end
234
+ lambda { subject.list nil }.must_output "Machines from machines.yml:\n machine_1\n machine_2\n"
256
235
  end
257
236
  end
258
237
 
@@ -264,7 +243,7 @@ describe Machines::Commandline do
264
243
  end
265
244
 
266
245
  it 'copies package to project folder' do
267
- override ['base']
246
+ subject.override ['base']
268
247
  File.exists?('packages/base.rb').must_equal true
269
248
  end
270
249
 
@@ -275,14 +254,14 @@ describe Machines::Commandline do
275
254
 
276
255
  it 'terminates when user answer no' do
277
256
  $input.string = "n\n"
278
- lambda { override ['base'] }.must_output 'Project package already exists. Overwrite? (y/n)
257
+ lambda { subject.override ['base'] }.must_output 'Project package already exists. Overwrite? (y/n)
279
258
  Aborted.
280
259
  '
281
260
  end
282
261
 
283
262
  it 'overwrites project package with default package' do
284
263
  $input.string = "y\n"
285
- lambda { override ['base'] }.must_output 'Project package already exists. Overwrite? (y/n)
264
+ lambda { subject.override ['base'] }.must_output 'Project package already exists. Overwrite? (y/n)
286
265
  Package copied to packages/base.rb
287
266
  '
288
267
  end
@@ -295,7 +274,7 @@ Package copied to packages/base.rb
295
274
  FileUtils.mkdir_p 'packages'
296
275
  FileUtils.touch File.join($conf.application_dir, 'packages', 'base.rb')
297
276
  FileUtils.touch File.join('packages', 'apps.rb')
298
- lambda { packages nil }.must_output 'Default packages
277
+ lambda { subject.packages nil }.must_output 'Default packages
299
278
  * base
300
279
  Project packages
301
280
  * apps
@@ -305,14 +284,14 @@ Project packages
305
284
 
306
285
  describe 'tasks' do
307
286
  it 'displays a list of tasks' do
308
- expects(:init)
309
- expects(:load_machinesfile)
287
+ subject.expects(:init)
288
+ Core.any_instance.expects(:package).with 'Machinesfile'
310
289
  $conf.tasks = {
311
290
  :task1 => {:description => 'description 1'},
312
291
  :task2 => {:description => 'description 2'},
313
292
  :task3 => {:description => 'description 3'}
314
293
  }
315
- lambda { tasks ['machine'] }.must_output 'Tasks
294
+ lambda { subject.tasks ['machine'] }.must_output 'Tasks
316
295
  task1 description 1
317
296
  task2 description 2
318
297
  task3 description 3