screwcap 0.3.5 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -1,5 +1,3 @@
1
- Gemfile
2
- Gemfile.lock
3
1
  History.txt
4
2
  Manifest.txt
5
3
  README.rdoc
@@ -8,23 +6,25 @@ TODO
8
6
  bin/screwcap
9
7
  lib/screwcap.rb
10
8
  lib/screwcap/base.rb
11
- lib/screwcap/deployer.rb
12
9
  lib/screwcap/message_logger.rb
13
10
  lib/screwcap/runner.rb
14
11
  lib/screwcap/sequence.rb
15
12
  lib/screwcap/server.rb
16
13
  lib/screwcap/task.rb
14
+ lib/screwcap/task_manager.rb
17
15
  lib/trollop.rb
18
16
  recipes/setup_rails.rb
17
+ runrdoc
19
18
  screwcap.gemspec
20
- spec/command_set_spec.rb
21
- spec/deployer_spec.rb
19
+ spec/runner_spec.rb
22
20
  spec/sequence_spec.rb
23
21
  spec/server_spec.rb
24
22
  spec/spec.opts
25
23
  spec/spec_helper.rb
24
+ spec/task_manager_spec.rb
26
25
  spec/task_spec.rb
27
26
  tasks/rspec.rake
27
+ test/config/bad_use.rb
28
28
  test/config/command_sets.rb
29
29
  test/config/expect.rb
30
30
  test/config/gateway.rb
@@ -32,9 +32,11 @@ test/config/local_task.rb
32
32
  test/config/no_server.rb
33
33
  test/config/rails_tasks.rb
34
34
  test/config/simple_recipe.rb
35
+ test/config/super_simple_recipe.rb
35
36
  test/config/undefined_command_set.rb
36
37
  test/config/undefined_item.rb
37
38
  test/config/undefined_server.rb
38
39
  test/config/unknown_use.rb
39
40
  test/config/upload.rb
40
41
  test/config/use.rb
42
+ test/config/use2.rb
data/README.rdoc CHANGED
@@ -20,6 +20,19 @@ For more info, see the main screwcap page at http://gammons.github.com/screwcap
20
20
 
21
21
  * gem install screwcap
22
22
 
23
+ == TODO:
24
+ * Explore removing the 'use' keyword, favoring require or load
25
+ * Add ability to parse user input
26
+ * Add ability to parse user input
27
+ * DONE add --dry-run to screwcap
28
+
29
+ == RECIPES:
30
+
31
+ === I need help writing rails recipes! Please help contribute some nice rock-solid rails recipes to the following repo:
32
+
33
+ http://github.com/gammons/screwcap_recipes
34
+
35
+
23
36
  == LICENSE:
24
37
 
25
38
  (The MIT License)
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ Hoe.plugin :newgem
11
11
  # Generate all the Rake tasks
12
12
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
13
  $hoe = Hoe.spec 'screwcap' do
14
- self.version = '0.3.5'
14
+ self.version = '0.5'
15
15
  self.developer 'Grant Ammons', 'grant@pipelinedeals.com'
16
16
  self.rubyforge_name = self.name # TODO this is default value
17
17
  self.extra_deps = [['net-ssh','>= 2.0.23'],['net-ssh-gateway','>=1.0.1'], ['net-scp','>=1.0.4']]
data/bin/screwcap CHANGED
@@ -4,14 +4,14 @@ require 'rubygems'
4
4
  require File.expand_path(File.dirname(__FILE__) + '/../lib/screwcap')
5
5
  require File.expand_path(File.dirname(__FILE__) + '/../lib/trollop')
6
6
 
7
-
8
7
  p = Trollop::Parser.new do
9
- opt :silent, "Be silent"
8
+ opt :silent, "Be silent", :short => "s"
10
9
  opt :nocolor, "Do not color output"
11
- opt :debug, "Turn on debugger. Will print full stacktrace if an exeception was raised"
12
- opt :help, "Show this message"
13
- opt :tasks, "Display available tasks in recipe file"
14
- opt :setup_rails, "Setup a rails app to use screwcap"
10
+ opt :debug, "Turn on debugger. Will print full stacktrace if an exeception was raised", :short => "d"
11
+ opt :help, "Show this message", :short => "h"
12
+ opt :tasks, "Display available tasks in recipe file", :short => "t"
13
+ opt :setup_rails, "Setup a rails app to use screwcap", :short => "r"
14
+ opt :dry_run, "Setup a rails app to use screwcap", :short => "n"
15
15
  version <<-EOF
16
16
  Screwcap #{Screwcap::VERSION} by Grant Ammons (grant@pipelinedeals.com)
17
17
  More info at http://gammons.github.com/screwcap
@@ -31,7 +31,7 @@ opts = Trollop::with_standard_exception_handling p do
31
31
 
32
32
  if opts[:tasks] == true
33
33
  recipe_file = ARGV.shift
34
- deployer = Deployer.new(opts.merge(:recipe_file => recipe_file))
34
+ deployer = TaskManager.new(opts.merge(:recipe_file => recipe_file))
35
35
  $stdout << "Tasks Available:\n" if deployer.__tasks.size > 0
36
36
  deployer.__tasks.map {|t| t.__name }.each {|name| $stdout << " #{name}\n" }
37
37
  $stdout << "Sequences Available:\n" if deployer.__sequences.size > 0
@@ -39,8 +39,23 @@ opts = Trollop::with_standard_exception_handling p do
39
39
  exit
40
40
  end
41
41
 
42
+ if opts[:dry_run] == true
43
+ recipe_file = ARGV.shift
44
+ deployer = TaskManager.new(opts.merge(:recipe_file => recipe_file))
45
+ ARGV.map {|a| a.to_sym }.each do |tname|
46
+ task = deployer.__tasks.find {|t| t.__name == tname }
47
+ raise(Screwcap::TaskNotFound, "Could not find task named '#{tname}' in the recipe file.") if task.nil?
48
+ $stdout << "\n*** BEGIN dry-run task #{task.__name}\n"
49
+ task.__commands.each do |cmd|
50
+ $stdout << " I: (dry-run): #{cmd[:command]}\n"
51
+ end
52
+ $stdout << "*** END dry-run task #{task.__name}\n"
53
+ end
54
+ exit
55
+ end
56
+
42
57
  if opts[:setup_rails] == true
43
- Deployer.new(:recipe_file => File.expand_path(File.dirname(__FILE__) + "/../recipes/setup_rails.rb")).run! :setup_rails
58
+ TaskManager.new(:recipe_file => File.expand_path(File.dirname(__FILE__) + "/../recipes/setup_rails.rb")).run! :setup_rails
44
59
  $stdout << "\nYour rails app now has a sample recipe, ready for the editing, in config/screwcap/recipe.rb\n"
45
60
  $stdout << "Your recipes will be automatically available in rake. Screwcap uses the :remote namespace.\n"
46
61
  $stdout << "To see what recipes you can run, type 'rake -T remote'.\n"
@@ -51,7 +66,7 @@ opts = Trollop::with_standard_exception_handling p do
51
66
  raise Trollop::HelpNeeded if ARGV.size < 2
52
67
  recipe_file = ARGV.shift
53
68
  begin
54
- Deployer.new(opts.merge(:recipe_file => recipe_file)).run! ARGV.map {|a| a.to_sym }
69
+ TaskManager.new(opts.merge(:recipe_file => recipe_file)).run! ARGV.map {|a| a.to_sym }
55
70
  rescue Exception => e
56
71
  raise e if opts[:debug] == true
57
72
  $stderr << e
data/lib/screwcap.rb CHANGED
@@ -13,10 +13,10 @@ require 'screwcap/task'
13
13
  require 'screwcap/server'
14
14
  require 'screwcap/runner'
15
15
  require 'screwcap/sequence'
16
- require 'screwcap/deployer'
16
+ require 'screwcap/task_manager'
17
17
 
18
18
  module Screwcap
19
- VERSION='0.3.5'
19
+ VERSION='0.5'
20
20
 
21
21
  class TaskNotFound < RuntimeError; end
22
22
  class NoServersDefined < Exception; end
data/lib/screwcap/base.rb CHANGED
@@ -3,5 +3,9 @@ module Screwcap
3
3
  def set(var, *args)
4
4
  method_missing((var.to_s + "=").to_sym, args.first)
5
5
  end
6
+
7
+ def clone_from(object)
8
+ object.table.each {|k,v| self.set(k,v) unless k.to_s[0..1] == "__" }
9
+ end
6
10
  end
7
11
  end
@@ -16,7 +16,7 @@ module MessageLogger
16
16
 
17
17
  def logmsg(msg, output, options)
18
18
  return if @options and @options[:silent] == true
19
- if @options and not @options[:nocolor] == true
19
+ unless (@options and @options[:nocolor] == true)
20
20
  case options[:color]
21
21
  when :blue
22
22
  output << "\033[0;36m#{msg}#{"\033[0m" if options[:clear]}"
@@ -1,63 +1,76 @@
1
1
  class Runner
2
2
  include MessageLogger
3
+ @@silent = false
3
4
 
4
- def self.execute! task, options
5
- @task = task; @options = options
6
- threads = []
7
- if @task.__options[:local] == true
8
- log "\n*** BEGIN executing local task #{@task.__name}\n", :color => :blue
9
- @task.__commands.each do |command|
10
- ret = `#{command[:command]}`
11
- if $?.to_i == 0
12
- log " I: (local): #{command[:command]}\n", :color => :blue
13
- log(" O: (local): #{ret}\n", :color => :blue) unless ret.nil? or ret == ""
14
- else
15
- log " I: (local): #{command[:command]}\n", :color => :blue
16
- errorlog(" O: (local): #{ret}\n", :color => :red) unless ret.nil? or ret == ""
17
- errorlog(" E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
5
+ def self.execute! options
6
+ @@silent = options[:silent]
7
+ begin
8
+ _log "\n*** BEGIN executing task #{options[:name]} on #{options[:server].name} with address #{options[:address]}\n", :color => :blue unless options[:silent] == true
9
+ options[:server].__with_connection_for(options[:address]) do |ssh|
10
+ options[:commands].each do |command|
11
+ ret = run_command(command, ssh, options)
12
+ break if ret != 0 and command[:abort_on_fail] == true
18
13
  end
19
14
  end
20
- log "\n*** END executing local task #{@task.__name}\n", :color => :blue
21
- else
22
- @task.__servers.each do |_server|
23
- _server.__addresses.each do |_address|
24
- if task.__options[:parallel] == false
25
- execute_on(_server, _address)
26
- else
27
- threads << Thread.new(_server, _address) { |server, address| execute_on(server, address) }
28
- end
29
- end
15
+ rescue Net::SSH::AuthenticationFailed => e
16
+ raise Net::SSH::AuthenticationFailed, "Authentication failed for server named #{server.name}. Please check your authentication credentials."
17
+ #rescue Exception => e
18
+ # _errorlog " F: (#{options[:address]}): #{e}", :color => :red
19
+ ensure
20
+ _log "*** END executing task #{options[:name]} on #{options[:server].name} with address #{options[:address]}\n\n", :color => :blue
21
+ end
22
+ options[:commands] # for tests
23
+ end
24
+
25
+ def self.execute_locally! options
26
+ @@silent = options[:silent]
27
+ _log "\n*** BEGIN executing local task #{options[:name]}\n", :color => :blue
28
+ options[:commands].each do |command|
29
+ command[:stdout] = ret = `#{command[:command]}`
30
+
31
+ if $?.to_i == 0
32
+ _log " I: (local): #{command[:command]}\n", :color => :blue
33
+ _log(" O: (local): #{ret}\n", :color => :blue) unless ret.nil? or ret == ""
34
+ else
35
+ _log " I: (local): #{command[:command]}\n", :color => :blue
36
+ _errorlog(" O: (local): #{ret}\n", :color => :red) unless ret.nil? or ret == ""
37
+ _errorlog(" E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
30
38
  end
31
39
  end
32
- threads.each {|t| t.join }
40
+ _log "\n*** END executing local task #{options[:name]}\n", :color => :blue
41
+ options[:commands]
33
42
  end
34
43
 
35
44
  private
36
45
 
37
- def self.execute_on(server, address)
38
- begin
39
- log "\n*** BEGIN executing task #{@task.__name} on #{server.name} with address #{address}\n", :color => :blue
40
-
41
- server.__with_connection_for(address) do |ssh|
42
- failed_command = nil
43
- @task.__commands.each do |command|
44
- if run_command(ssh, address, server, command) != 0 and command[:onfailure]
45
- failed_command = command
46
- break
47
- end
48
- end
49
- if failed_command
50
- @task.__commands = []
51
- @task.send(failed_command[:onfailure])
52
- @task.__commands.each { |command| run_command(ssh, address, server, command) }
53
- end
46
+ def self.run_command(command, ssh, options)
47
+ if command[:type] == :remote
48
+ _log " I: (#{options[:address]}): #{command[:command]}\n", :color => :green
49
+ stdout, stderr, exit_code, exit_signal = ssh_exec! ssh, command[:command]
50
+ command[:stdout] = stdout
51
+ command[:stderr] = stderr
52
+ _log(" O: (#{options[:address]}): #{stdout}", :color => :green) unless stdout.nil? or stdout == ""
53
+ _errorlog(" O: (#{options[:address]}): #{stderr}", :color => :red) unless stderr.nil? or stderr == ""
54
+ _errorlog(" E: (#{options[:address]}): #{command[:command]} return exit code: #{exit_code}\n", :color => :red) if exit_code != 0
55
+ return exit_code
56
+ elsif command[:type] == :local
57
+ ret = `#{command[:command]}`
58
+ command[:stdout] = ret
59
+ if $?.to_i == 0
60
+ _log " I: (local): #{command[:command]}\n", :color => :blue
61
+ _log " O: (local): #{ret}\n", :color => :blue
62
+ else
63
+ _log " I: (local): #{command[:command]}\n", :color => :blue
64
+ _errorlog " O: (local): #{ret}\n", :color => :red
65
+ _errorlog(" E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
54
66
  end
55
- rescue Net::SSH::AuthenticationFailed => e
56
- raise Net::SSH::AuthenticationFailed, "Authentication failed for server named #{server.name}. Please check your authentication credentials."
57
- rescue Exception => e
58
- errorlog " F: (#{address}): #{e}", :color => :red
59
- ensure
60
- log "*** END executing task #{@task.__name} on #{server.name} with address #{address}\n\n", :color => :blue
67
+ return $?
68
+ elsif command[:type] == :scp
69
+ _log " I: (#{options[:address]}): SCP #{command[:local]} to #{options[:server].__user}@#{options[:address]}:#{command[:remote]}\n", :color => :green
70
+ options[:server].__upload_to!(options[:address], command[:local], command[:remote])
71
+
72
+ # this will need to be improved to allow for :onfailure
73
+ return 0
61
74
  end
62
75
  end
63
76
 
@@ -91,33 +104,13 @@ class Runner
91
104
  [stdout_data, stderr_data, exit_code, exit_signal]
92
105
  end
93
106
 
107
+ def self._log(message, options)
108
+ return if @@silent == true
109
+ log(message, options)
110
+ end
94
111
 
95
- def self.run_command(ssh, address, server, command)
96
- if command[:type] == :remote
97
- log " I: (#{address}): #{command[:command]}\n", :color => :green
98
- stdout, stderr, exit_code, exit_signal = ssh_exec! ssh, command[:command]
99
- log(" O: (#{address}): #{stdout}", :color => :green) unless stdout.nil? or stdout == ""
100
- errorlog(" O: (#{address}): #{stderr}", :color => :red) unless stderr.nil? or stderr == ""
101
- errorlog(" E: (#{address}): #{command[:command]} return exit code: #{exit_code}\n", :color => :red) if exit_code != 0
102
- return exit_code
103
- elsif command[:type] == :local
104
- ret = `#{command[:command]}`
105
- if $?.to_i == 0
106
- log " I: (local): #{command[:command]}\n", :color => :blue
107
- log " O: (local): #{ret}\n", :color => :blue
108
- else
109
- log " I: (local): #{command[:command]}\n", :color => :blue
110
- errorlog " O: (local): #{ret}\n", :color => :red
111
- errorlog(" E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
112
- end
113
- return $?
114
- elsif command[:type] == :scp
115
- log " I: (#{address}): SCP #{command[:local]} to #{server.__user}@#{address}:#{command[:remote]}\n", :color => :green
116
- server.__upload_to!(address, command[:local], command[:remote])
117
-
118
- # this will need to be improved to allow for :onfailure
119
- return 0
120
- end
121
-
112
+ def self._errorlog(message, options)
113
+ return if @@silent == true
114
+ errorlog(message, options)
122
115
  end
123
116
  end
@@ -23,16 +23,6 @@ class Sequence < Screwcap::Base
23
23
  super
24
24
  self.__options = opts
25
25
  self.__name = opts[:name]
26
- self.__deployment_task_names = opts[:deployment_task_names]
27
26
  self.__task_names = opts[:tasks]
28
- validate
29
- end
30
-
31
- private
32
-
33
- def validate
34
- self.__task_names.each do |tn|
35
- raise(Screwcap::ConfigurationError, "Could not find task #{tn} in the deployment recipe.") unless self.__deployment_task_names.include?(tn)
36
- end
37
27
  end
38
28
  end
@@ -13,11 +13,14 @@ class Server < Screwcap::Base
13
13
  # * *:password* specify the password to connect with. Not recommended. Use keys.
14
14
  def initialize(opts = {})
15
15
  super
16
+ self.__name = opts.delete(:name)
17
+ self.__user = opts.delete(:user)
18
+ self.__options[:keys] = [opts.delete(:key)] if opts[:key]
19
+
20
+ servers = opts.delete(:servers)
21
+ self.__gateway = servers.select {|s| s.__options[:is_gateway] == true }.find {|s| s.__name == opts[:gateway] } if servers
22
+
16
23
  self.__options = opts
17
- self.__name = opts[:name]
18
- self.__servers = opts[:servers]
19
- self.__user = opts[:user]
20
- self.__options[:keys] = [self.__options.delete(:key)] if self.__options[:key]
21
24
 
22
25
  if self.__options[:address] and self.__options[:addresses].nil?
23
26
  self.__addresses = [self.__options.delete(:address)]
@@ -31,9 +34,8 @@ class Server < Screwcap::Base
31
34
  end
32
35
 
33
36
  def __with_connection_for(address, &block)
34
- if self.__options[:gateway]
35
- gateway = self.__servers.select {|s| s.__options[:is_gateway] == true }.find {|s| s.__name == self.__options[:gateway] }
36
- gateway.__get_gateway_connection.ssh(address, self.__user, options_for_net_ssh) do |ssh|
37
+ if self.__gateway
38
+ __gateway.__get_gateway_connection.ssh(address, self.__user, options_for_net_ssh) do |ssh|
37
39
  yield ssh
38
40
  end
39
41
  else
data/lib/screwcap/task.rb CHANGED
@@ -3,21 +3,11 @@ class Task < Screwcap::Base
3
3
 
4
4
  def initialize(opts = {}, &block)
5
5
  super
6
- self.__name = opts[:name]
6
+ self.__name = opts.delete(:name)
7
7
  self.__options = opts
8
8
  self.__commands = []
9
- self.__command_sets = opts[:command_sets] || []
10
- self.__server_names = []
11
- self.__block = block if opts[:command_set] == true
12
-
13
-
14
- if opts[:server] and opts[:servers].nil?
15
- self.__server_names << opts[:server]
16
- else
17
- self.__server_names = opts[:servers]
18
- end
19
-
20
- validate(opts[:deployment_servers]) unless opts[:validate] == false or opts[:local] == true
9
+ self.__servers = opts.delete(:servers)
10
+ self.__block = block
21
11
  end
22
12
 
23
13
  # Run a command. This can either be a string, or a symbol that is the name of a command set to run.
@@ -45,8 +35,8 @@ class Task < Screwcap::Base
45
35
  # task_for :item, :servers => :server do
46
36
  # run "ls -l", :onfailure => :rollback
47
37
  # end
38
+
48
39
  def run arg, options = {}
49
-
50
40
  if arg.class == Symbol
51
41
  self.__commands << options.merge({:command => self.send(arg), :type => :remote, :from => self.__name})
52
42
  else
@@ -58,6 +48,7 @@ class Task < Screwcap::Base
58
48
  # task_for :item, :servers => :server do
59
49
  # scp :local => "/tmp/pirate_booty", :remote => "/mnt/app/config/booty.yml"
60
50
  # end
51
+
61
52
  def scp options = {}
62
53
  self.__commands << options.merge({:type => :scp})
63
54
  end
@@ -78,54 +69,68 @@ class Task < Screwcap::Base
78
69
  # task_for :item, :servers => :server do
79
70
  # local "herd_cats", :onfailure => :rollback
80
71
  # end
72
+
81
73
  def local arg, options = {}
82
74
  if arg.class == Symbol
83
75
  self.__commands << options.merge({:command => self.send(arg), :type => :local, :from => self.__name})
84
76
  else
85
77
  self.__commands << options.merge({:command => arg, :type => :local, :from => self.__name})
86
78
  end
87
- if failure_cmd = self.__commands.last[:onfailure]
88
- unless self.__command_sets.find {|cs| cs.__name == failure_cmd }
89
- raise ScrewCap::ConfigurationError, "Could not find failure command set named '#{failure_cmd}' for task '#{self.__name}'"
90
- end
91
- end
92
79
  end
93
80
 
94
- protected
81
+ def __build_commands(command_sets = [])
82
+ commands = []
95
83
 
96
- def method_missing(m, *args) # :nodoc
97
- if m.to_s[0..1] == "__" or [:run].include?(m) or m.to_s.reverse[0..0] == "="
98
- super(m, args.first)
99
- else
100
- if cs = self.__command_sets.find {|cs| cs.__name == m }
101
- # eval what is in the block
102
- clone_table_for(cs)
103
- cs.__commands = []
104
- cs.instance_eval(&cs.__block)
105
- self.__commands += cs.__commands
84
+ self.instance_eval(&self.__block)
85
+
86
+ # :before for before_ callback
87
+ if before = command_sets.find {|cs| cs.__name.to_s == "before_#{self.__name}" or cs.__name == self.__options[:before] } and before != self
88
+ before.clone_from(self)
89
+ commands << before.__build_commands(command_sets)
90
+ end
91
+
92
+ self.__commands.each do |command|
93
+ if command[:type] == :unknown
94
+ if cs = command_sets.find {|cs| cs.__name == command[:command] }
95
+ cs.clone_from(self)
96
+ commands << cs.__build_commands(command_sets)
97
+ else
98
+ raise(NoMethodError, "Cannot find task, command set, or other method named '#{command[:command]}'")
99
+ end
106
100
  else
107
- raise NoMethodError, "Undefined method '#{m.to_s}' for task :#{self.name.to_s}"
101
+ commands << command
108
102
  end
109
103
  end
110
- end
111
-
112
- private
113
104
 
114
- def clone_table_for(object)
115
- self.table.each do |k,v|
116
- object.set(k, v) unless [:__block, :__tasks, :__name, :__command_sets, :__commands, :__options].include?(k)
105
+ # :after for after_ callback
106
+ if after = command_sets.find {|cs| cs.__name.to_s == "after_#{self.__name}" or cs.__name == self.__options[:after] } and after != self
107
+ after.clone_from(self)
108
+ commands << after.__build_commands(command_sets)
117
109
  end
110
+
111
+ commands.flatten
118
112
  end
119
113
 
120
114
  def validate(servers)
121
- raise Screwcap::ConfigurationError, "Could not find a server to run this task on. Please specify :server => :servername or :servers => [:server1, :server2] in the task_for directive." if self.__server_names.nil? or self.__server_names == []
115
+ raise Screwcap::ConfigurationError, "Could not find a server to run this task on. Please specify :server => :servername or :servers => [:server1, :server2] in the task_for directive." if servers == [] or servers.nil?
122
116
 
123
- self.__server_names.each do |server_name|
124
- raise Screwcap::ConfigurationError, "Could not find a server to run this task on. Please specify :server => :servername or :servers => [:server1, :server2] in the task_for directive." unless servers.map(&:name).include?(server_name)
125
- end
117
+ # marshal :server into :servers
118
+ self.__servers = [self.__options.delete(:server)] if self.__options[:server]
119
+ self.__servers = [self.__servers] if self.__servers.class != Array
126
120
 
127
- # finally map the actual server objects via name
128
- self.__servers = self.__server_names.map {|name| servers.find {|s| s.name == name } }
121
+ server_names = servers.map {|s| s.__name }
122
+ self.__servers.each do |server_name|
123
+ raise Screwcap::ConfigurationError, "Could not find a server to run this task on. Please specify :server => :servername or :servers => [:server1, :server2] in the task_for directive." unless server_names.include?(server_name)
124
+ end
129
125
  end
130
126
 
127
+ private
128
+
129
+ def method_missing(m, *args) # :nodoc
130
+ if m.to_s[0..1] == "__" or [:run].include?(m) or m.to_s.reverse[0..0] == "="
131
+ super(m, args.first)
132
+ else
133
+ self.__commands << {:command => m, :type => :unknown, :from => self.__name}
134
+ end
135
+ end
131
136
  end