automateit 0.71006 → 0.71012
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGES.txt +12 -0
- data/Rakefile +6 -1
- data/TODO.txt +10 -2
- data/lib/automateit/account_manager/linux.rb +4 -2
- data/lib/automateit/address_manager.rb +2 -82
- data/lib/automateit/address_manager/base.rb +148 -0
- data/lib/automateit/address_manager/linux.rb +8 -46
- data/lib/automateit/address_manager/sunos.rb +46 -0
- data/lib/automateit/interpreter.rb +4 -0
- data/lib/automateit/platform_manager.rb +1 -0
- data/lib/automateit/platform_manager/darwin.rb +2 -2
- data/lib/automateit/platform_manager/freebsd.rb +4 -0
- data/lib/automateit/platform_manager/sunos.rb +39 -0
- data/lib/automateit/plugin/driver.rb +21 -4
- data/lib/automateit/plugin/manager.rb +2 -1
- data/lib/automateit/root.rb +1 -1
- data/lib/automateit/service_manager/sysv.rb +2 -1
- data/lib/automateit/shell_manager.rb +3 -0
- data/lib/automateit/shell_manager/portable.rb +22 -14
- data/lib/automateit/template_manager.rb +4 -3
- data/lib/automateit/template_manager/base.rb +13 -7
- data/spec/breaker.rb +8 -0
- data/spec/integration/{address_manager_linux_spec.rb → address_manager_spec.rb} +65 -25
- data/spec/integration/package_manager_spec.rb +4 -0
- data/spec/integration/service_manager_sysv_spec.rb +92 -34
- data/spec/integration/template_manager_erb_spec.rb +22 -5
- data/spec/unit/plugins_spec.rb +5 -0
- data/spec/unit/template_manager_erb_spec.rb +4 -0
- metadata +9 -4
- metadata.gz.sig +0 -0
@@ -2,10 +2,10 @@
|
|
2
2
|
#
|
3
3
|
# A PlatformManager driver for Apple's Darwin.
|
4
4
|
class AutomateIt::PlatformManager::Darwin < AutomateIt::PlatformManager::Struct
|
5
|
-
depends_on :files => ["/usr/sbin/scutil"], :programs => ["which"]
|
5
|
+
depends_on :files => ["/usr/sbin/scutil"], :programs => ["which", "uname"]
|
6
6
|
|
7
7
|
def suitability(method, *args) # :nodoc:
|
8
|
-
# Must be higher than PlatformManager::
|
8
|
+
# Must be higher than PlatformManager::Uname
|
9
9
|
return available? ? 3 : 0
|
10
10
|
end
|
11
11
|
|
@@ -2,6 +2,10 @@
|
|
2
2
|
#
|
3
3
|
# A PlatformManager driver for FreeBSD.
|
4
4
|
class AutomateIt::PlatformManager::FreeBSD < AutomateIt::PlatformManager::Uname
|
5
|
+
def self.token
|
6
|
+
:freebsd
|
7
|
+
end
|
8
|
+
|
5
9
|
depends_on :files => %w(/etc/portsnap.conf /etc/rc.conf)
|
6
10
|
|
7
11
|
def suitability(method, *args) # :nodoc:
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# == PlatformManager::SunOS
|
2
|
+
#
|
3
|
+
# A PlatformManager driver for SunOS.
|
4
|
+
class AutomateIt::PlatformManager::SunOS < AutomateIt::PlatformManager::Uname
|
5
|
+
def self.token
|
6
|
+
:sunos
|
7
|
+
end
|
8
|
+
|
9
|
+
depends_on \
|
10
|
+
:programs => %w(uname),
|
11
|
+
:callbacks => [lambda {
|
12
|
+
begin
|
13
|
+
not `uname -s`.match(/SunOS/i).nil?
|
14
|
+
rescue
|
15
|
+
false
|
16
|
+
end
|
17
|
+
}]
|
18
|
+
|
19
|
+
def suitability(method, *args) # :nodoc:
|
20
|
+
# Must be higher than PlatformManager::Struct and Uname
|
21
|
+
return available? ? 3 : 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def _prepare
|
25
|
+
return if @struct[:release]
|
26
|
+
@struct[:distro] = "sun"
|
27
|
+
@struct[:release] = `uname -r`.strip.downcase
|
28
|
+
@struct
|
29
|
+
end
|
30
|
+
|
31
|
+
def query(search)
|
32
|
+
_prepare
|
33
|
+
super(search)
|
34
|
+
end
|
35
|
+
|
36
|
+
def single_vendor?
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
end
|
@@ -45,6 +45,18 @@ module AutomateIt
|
|
45
45
|
cattr_accessor :classes
|
46
46
|
self.classes = {}
|
47
47
|
|
48
|
+
# Returns the Plugin::Manager instance for this Driver.
|
49
|
+
attr_accessor :manager
|
50
|
+
|
51
|
+
# Setup a Driver.
|
52
|
+
#
|
53
|
+
# Options:
|
54
|
+
# * :manager -- The Plugin::Manager instance controlling this driver.
|
55
|
+
def setup(opts={})
|
56
|
+
self.manager = opts[:manager] if opts[:manager]
|
57
|
+
super(opts)
|
58
|
+
end
|
59
|
+
|
48
60
|
# Retrieve the manager token for this driver
|
49
61
|
def self.manager_token
|
50
62
|
fragments = base_driver.to_s.split(/::/)
|
@@ -70,10 +82,14 @@ module AutomateIt
|
|
70
82
|
if subclass.base_driver?
|
71
83
|
# Ignore, base drivers should never be registered
|
72
84
|
elsif base_driver
|
73
|
-
|
74
|
-
classes[
|
75
|
-
|
76
|
-
|
85
|
+
manager_token = subclass.manager_token
|
86
|
+
classes[manager_token] ||= []
|
87
|
+
|
88
|
+
unless classes[manager_token].include?(subclass)
|
89
|
+
classes[manager_token] << subclass
|
90
|
+
end
|
91
|
+
|
92
|
+
### puts "manager_token %s / driver %s" % [manager_token, subclass]
|
77
93
|
else
|
78
94
|
# XXX Should this really raise an exception?
|
79
95
|
raise TypeError.new("Can't determine manager for driver: #{subclass}")
|
@@ -197,6 +213,7 @@ module AutomateIt
|
|
197
213
|
raise NotImplementedError.new("Missing dependencies -- %s" % msg)
|
198
214
|
end
|
199
215
|
end
|
216
|
+
protected :_raise_unless_available
|
200
217
|
|
201
218
|
# What is this driver's suitability for automatic detection? The Manager
|
202
219
|
# queries its drivers when there isn't a driver specified with a
|
@@ -80,7 +80,8 @@ module AutomateIt
|
|
80
80
|
end
|
81
81
|
self.class.driver_classes.each do |driver_class|
|
82
82
|
driver_token = driver_class.token
|
83
|
-
@drivers[driver_token].setup(
|
83
|
+
@drivers[driver_token].setup(
|
84
|
+
:interpreter => @interpreter, :manager => self)
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
data/lib/automateit/root.rb
CHANGED
@@ -60,7 +60,7 @@ class AutomateIt::ServiceManager::SYSV < AutomateIt::ServiceManager::BaseDriver
|
|
60
60
|
end
|
61
61
|
|
62
62
|
result = tell(service, :status, :check => true)
|
63
|
-
|
63
|
+
nitpick("_sash top: k=%s r=%s e=%s" % [kind, result, expected])
|
64
64
|
return result if expected == result
|
65
65
|
if opts[:wait]
|
66
66
|
timeout = Time.now + opts[:wait]
|
@@ -69,6 +69,7 @@ class AutomateIt::ServiceManager::SYSV < AutomateIt::ServiceManager::BaseDriver
|
|
69
69
|
[kind, service, timeout - Time.now])
|
70
70
|
sleep 0.5
|
71
71
|
result = tell(service, :status, :check => true)
|
72
|
+
nitpick("_sash rep: k=%s r=%s e=%s" % [kind, result, expected])
|
72
73
|
break if expected == result
|
73
74
|
end
|
74
75
|
log.info(PNOTE+" ServiceManager#%s finished waiting for '%s', got: %s" %
|
@@ -28,6 +28,9 @@ class AutomateIt::ShellManager < AutomateIt::Plugin::Manager
|
|
28
28
|
|
29
29
|
# Backup +sources+ if they exist. Returns the names of the backups created.
|
30
30
|
#
|
31
|
+
# Options:
|
32
|
+
# * :quiet -- Don't display output? Default is false.
|
33
|
+
#
|
31
34
|
# These backups are copies of the original sources saved into the same
|
32
35
|
# directories as the originals. The pathnames of these copies are timestamped
|
33
36
|
# and guaranteed to be unique, so you can have multiple backups of the same
|
@@ -30,6 +30,8 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
|
30
30
|
|
31
31
|
# See ShellManager#backup
|
32
32
|
def backup(*sources)
|
33
|
+
sources, opts = args_and_opts(*sources)
|
34
|
+
|
33
35
|
targets = []
|
34
36
|
for source in sources
|
35
37
|
is_dir = File.directory?(source)
|
@@ -46,17 +48,19 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
|
46
48
|
|
47
49
|
target = ::Tempster.tempster(tempster_opts)
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
log.silence(opts[:quiet] ? Logger::WARN : log.level) do
|
52
|
+
if is_dir
|
53
|
+
cp_opts = {}
|
54
|
+
cp_opts[:recursive] = true if is_dir
|
55
|
+
cp_opts[:preserve] = :try
|
53
56
|
|
54
|
-
|
55
|
-
|
57
|
+
source_children = _directory_contents(source)
|
58
|
+
#puts "sc: %s" % source_children.inspect
|
56
59
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
+
interpreter.cp_r(source_children, target, cp_opts)
|
61
|
+
else
|
62
|
+
interpreter.cp(source, target)
|
63
|
+
end
|
60
64
|
end
|
61
65
|
|
62
66
|
targets << target
|
@@ -393,6 +397,8 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
|
393
397
|
end
|
394
398
|
|
395
399
|
modified_entries = []
|
400
|
+
modified_ownership = false
|
401
|
+
modified_permission = false
|
396
402
|
Find.find(*targets) do |path|
|
397
403
|
modified = false
|
398
404
|
stat = writing? || File.exists?(path) ? File.stat(path) : nil
|
@@ -401,15 +407,18 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
|
401
407
|
mode = opts[:mode] | (stat.directory? ? DIRECTORY_MASK : FILE_MASK) if stat
|
402
408
|
unless stat and (mode ^ stat.mode).zero?
|
403
409
|
modified = true
|
410
|
+
modified_permission = true
|
404
411
|
File.chmod(mode, path) if writing?
|
405
412
|
end
|
406
413
|
end
|
407
414
|
if user and (not stat or user != stat.uid)
|
408
415
|
modified = true
|
416
|
+
modified_ownership = true
|
409
417
|
File.chown(user, nil, path) if writing?
|
410
418
|
end
|
411
419
|
if group and (not stat or group != stat.gid)
|
412
420
|
modified = true
|
421
|
+
modified_ownership = true
|
413
422
|
File.chown(nil, group, path) if writing?
|
414
423
|
end
|
415
424
|
modified_entries << path if modified
|
@@ -421,19 +430,18 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
|
421
430
|
display_entries = opts[:details] ? modified_entries : targets
|
422
431
|
display_entries = [display_entries].flatten
|
423
432
|
|
424
|
-
if
|
433
|
+
if modified_permission
|
425
434
|
msg = "chmod"
|
426
435
|
msg << " -R" if opts[:recursive]
|
427
436
|
msg << " 0%o" % opts[:mode] if opts[:mode]
|
428
437
|
msg << " " << display_entries.join(' ')
|
429
438
|
log.info(PEXEC+msg)
|
430
439
|
end
|
431
|
-
if
|
440
|
+
if modified_ownership
|
432
441
|
msg = "chown"
|
433
442
|
msg << " -R" if opts[:recursive]
|
434
443
|
msg << " %s" % opts[:user] if opts[:user]
|
435
444
|
msg << ":" if opts[:user] and opts[:group]
|
436
|
-
msg << " " unless opts[:user] and opts[:group]
|
437
445
|
msg << "%s" % opts[:group] if opts[:group]
|
438
446
|
msg << " " << display_entries.join(' ')
|
439
447
|
log.info(PEXEC+msg)
|
@@ -484,11 +492,11 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
|
484
492
|
end
|
485
493
|
|
486
494
|
unless quiet
|
487
|
-
msg =
|
495
|
+
msg = "touch"
|
488
496
|
msg << " --reference %s" % like if like
|
489
497
|
msg << " --stamp %s" % stamp if stamp
|
490
498
|
msg << " " << [targets].flatten.join(" ")
|
491
|
-
log.info(msg)
|
499
|
+
log.info(PEXEC+msg)
|
492
500
|
end
|
493
501
|
|
494
502
|
results = []
|
@@ -17,9 +17,10 @@ class AutomateIt::TemplateManager < AutomateIt::Plugin::Manager
|
|
17
17
|
# * :text -- Read the template from this string.
|
18
18
|
# * :to -- Render to a file, otherwise returns the rendered string.
|
19
19
|
# * :locals -- Hash of variables passed to template as local variables.
|
20
|
-
# * :dependencies --
|
21
|
-
#
|
22
|
-
# * :
|
20
|
+
# * :dependencies -- Array of filenames to check timestamps on, only used
|
21
|
+
# when :check is :timestamp.
|
22
|
+
# * :backup -- Make a backup? Default is true.
|
23
|
+
# * :force -- Render without making a check. Default is false.
|
23
24
|
# * :check -- Determines when to render, otherwise uses value of
|
24
25
|
# +default_check+, possible values:
|
25
26
|
# * :compare -- Only render if rendered template is different than the
|
@@ -16,6 +16,10 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
#.......................................................................
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
19
23
|
# Return Array of +dependencies+ newer than +filename+. Will be empty if
|
20
24
|
# +filename+ is newer than all of the +dependencies+.
|
21
25
|
def _newer(filename, *dependencies)
|
@@ -26,13 +30,11 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
|
|
26
30
|
end
|
27
31
|
return updated
|
28
32
|
end
|
29
|
-
protected :_newer
|
30
33
|
|
31
34
|
# Does +filename+ exist?
|
32
35
|
def _exists?(filename)
|
33
36
|
return File.exists?(filename)
|
34
37
|
end
|
35
|
-
protected :_exists?
|
36
38
|
|
37
39
|
# Return the contents of +filename+.
|
38
40
|
def _read(filename)
|
@@ -47,20 +49,22 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
50
|
-
protected :_read
|
51
52
|
|
52
53
|
# Write +contents+ to +filename+.
|
53
54
|
def _write(filename, contents)
|
54
55
|
File.open(filename, "w+"){|writer| writer.write(contents)} if writing?
|
55
56
|
return true
|
56
57
|
end
|
57
|
-
|
58
|
+
|
59
|
+
# Backup +filename+.
|
60
|
+
def _backup(filename)
|
61
|
+
interpreter.backup(filename)
|
62
|
+
end
|
58
63
|
|
59
64
|
# Return the modification date for +filename+.
|
60
65
|
def _mtime(filename)
|
61
66
|
return _exists? ? File.mtime(filename) : nil
|
62
67
|
end
|
63
|
-
protected :_mtime
|
64
68
|
|
65
69
|
# Render a template specified in the block. It takes the same arguments and
|
66
70
|
# returns the same results as the #render call.
|
@@ -84,6 +88,7 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
|
|
84
88
|
source_filename = args[0] || opts[:file]
|
85
89
|
target_filename = args[1] || opts[:to]
|
86
90
|
source_text = opts[:text]
|
91
|
+
opts[:backup] = true if opts[:backup].nil?
|
87
92
|
|
88
93
|
raise ArgumentError.new("No source specified with :file or :text") if not source_filename and not source_text
|
89
94
|
raise Errno::ENOENT.new(source_filename) if writing? and source_filename and not _exists?(source_filename)
|
@@ -155,11 +160,13 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
|
|
155
160
|
log.debug(PNOTE+"Rendering for '#{target_filename}' skipped because contents are the same")
|
156
161
|
return false
|
157
162
|
else
|
158
|
-
log.info(PNOTE+"Rendering '#{target_filename} because its contents changed")
|
163
|
+
log.info(PNOTE+"Rendering '#{target_filename}' because its contents changed")
|
159
164
|
end
|
160
165
|
when :timestamp
|
161
166
|
log.info(PNOTE+"Rendering '#{target_filename}' because of updated: #{updates.join(' ')}")
|
162
167
|
end
|
168
|
+
|
169
|
+
_backup(target_filename) if target_exists and opts[:backup]
|
163
170
|
result = _write(target_filename, output)
|
164
171
|
return result
|
165
172
|
ensure
|
@@ -168,5 +175,4 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
|
|
168
175
|
end
|
169
176
|
end
|
170
177
|
end
|
171
|
-
protected :_render_helper
|
172
178
|
end
|
data/spec/breaker.rb
ADDED
@@ -4,34 +4,26 @@ if not INTERPRETER.euid?
|
|
4
4
|
puts "NOTE: Can't check 'euid' on this platform, #{__FILE__}"
|
5
5
|
elsif not INTERPRETER.superuser?
|
6
6
|
puts "NOTE: Must be root to check #{__FILE__}"
|
7
|
-
elsif not INTERPRETER.address_manager[:linux].available?
|
8
|
-
puts "NOTE: Can't check AddressManager::Linux on this platform, #{__FILE__}"
|
9
7
|
else
|
10
|
-
describe
|
8
|
+
describe AutomateIt::AddressManager, :shared => true do
|
11
9
|
before(:all) do
|
10
|
+
# Should examples be independent? True is correct and lets you run a
|
11
|
+
# single example. False is evil and requires you to run the entire suite,
|
12
|
+
# but it's much faster. On Linux false yields a 5x speed-up.
|
13
|
+
@independent = false
|
14
|
+
|
12
15
|
@a = AutomateIt.new(:verbosity => Logger::WARN)
|
13
16
|
@m = @a.address_manager
|
14
|
-
|
15
|
-
@properties = {
|
16
|
-
:device => "eth0",
|
17
|
-
:label => "xxxx",
|
18
|
-
:address => "10.0.0.249",
|
19
|
-
:mask => "24",
|
20
|
-
:announcements => 1,
|
21
|
-
}
|
22
|
-
|
23
|
-
@device_and_label = @properties[:device]+":"+@properties[:label]
|
24
|
-
|
25
|
-
if @m.interfaces.include?(@device_and_label) \
|
26
|
-
or @m.addresses.include?(@properties[:address])
|
27
|
-
raise "ERROR: This computer already has the device/address used for testing! Either disable #{@device_and_label} and #{@properties[:address]}, or change the spec to test using different properties."
|
28
|
-
end
|
29
17
|
end
|
30
18
|
|
31
19
|
after(:all) do
|
32
20
|
@m.remove(@properties)
|
33
21
|
end
|
34
22
|
|
23
|
+
after(:each) do
|
24
|
+
@m.remove(@properties) if @independent
|
25
|
+
end
|
26
|
+
|
35
27
|
it "should find interfaces for top-level device" do
|
36
28
|
@m.interfaces.should include(@properties[:device])
|
37
29
|
end
|
@@ -50,36 +42,41 @@ else
|
|
50
42
|
|
51
43
|
it "should add an address" do
|
52
44
|
@m.add(@properties).should be_true
|
53
|
-
# Leaves active interface behind for other tests
|
54
45
|
end
|
55
46
|
|
56
47
|
it "should find added interface" do
|
57
|
-
|
48
|
+
@m.add(@properties).should be_true if @independent
|
49
|
+
|
58
50
|
@m.interfaces.should include(@device_and_label)
|
59
51
|
end
|
60
52
|
|
61
53
|
it "should find added IP address" do
|
62
|
-
|
54
|
+
@m.add(@properties).should be_true if @independent
|
55
|
+
|
63
56
|
@m.addresses.should include(@properties[:address])
|
64
57
|
end
|
65
58
|
|
66
59
|
it "should find added address using a properties bundle" do
|
67
|
-
|
60
|
+
@m.add(@properties).should be_true if @independent
|
61
|
+
|
68
62
|
@m.has?(@properties).should be_true
|
69
63
|
end
|
70
64
|
|
71
65
|
it "should find added address using the IP address" do
|
72
|
-
|
66
|
+
@m.add(@properties).should be_true if @independent
|
67
|
+
|
73
68
|
@m.has?(:address => @properties[:address]).should be_true
|
74
69
|
end
|
75
70
|
|
76
71
|
it "should find added address using device and label" do
|
77
|
-
|
72
|
+
@m.add(@properties).should be_true if @independent
|
73
|
+
|
78
74
|
@m.has?(:device => @properties[:device], :label => @properties[:label]).should be_true
|
79
75
|
end
|
80
76
|
|
81
77
|
it "should remove an address" do
|
82
|
-
|
78
|
+
@m.add(@properties).should be_true if @independent
|
79
|
+
|
83
80
|
@m.remove(@properties).should be_true
|
84
81
|
end
|
85
82
|
|
@@ -116,4 +113,47 @@ else
|
|
116
113
|
@m.hostnames_for("kagami").should == ["kagami"]
|
117
114
|
end
|
118
115
|
end
|
116
|
+
|
117
|
+
#---[ Targets ]---------------------------------------------------------
|
118
|
+
|
119
|
+
%w(linux sunos).each do |driver_name|
|
120
|
+
driver_token = driver_name.to_sym
|
121
|
+
driver = INTERPRETER.address_manager[driver_token]
|
122
|
+
if driver.available?
|
123
|
+
describe driver.class.to_s do
|
124
|
+
it_should_behave_like "AutomateIt::AddressManager"
|
125
|
+
|
126
|
+
before(:all) do
|
127
|
+
|
128
|
+
@properties = {
|
129
|
+
:device => @m.interfaces.reject{|t| t =~ /^lo\d+$/}.first,
|
130
|
+
:label => "1",
|
131
|
+
:address => "10.0.0.249",
|
132
|
+
:mask => "24",
|
133
|
+
}
|
134
|
+
|
135
|
+
case driver_token
|
136
|
+
when :sunos
|
137
|
+
# Accept defaults
|
138
|
+
when :linux
|
139
|
+
@properties[:label] = "atst"
|
140
|
+
@properties[:announcements] = 1
|
141
|
+
else
|
142
|
+
raise ArgumentError.new("Unknown AddressManager driver: #{driver_token}")
|
143
|
+
end
|
144
|
+
|
145
|
+
@device_and_label = @properties[:device]+":"+@properties[:label]
|
146
|
+
|
147
|
+
if @m.interfaces.include?(@device_and_label) \
|
148
|
+
or @m.addresses.include?(@properties[:address])
|
149
|
+
raise "ERROR: This computer already has the device/address used for testing! Either disable #{@device_and_label} and #{@properties[:address]}, or change the spec to test using different properties."
|
150
|
+
end
|
151
|
+
|
152
|
+
@d = @m[driver_token]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
else
|
156
|
+
puts %{NOTE: Can't check %s on this platform, #{__FILE__}} % driver.class
|
157
|
+
end
|
158
|
+
end
|
119
159
|
end
|