instalatron 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.5.2"
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Abiquo Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = instalatron
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to instalatron
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Sergio Rubio. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'lib/instalatron.rb'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'rake'
12
+
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.version = Instalatron::VERSION
17
+ gem.name = "instalatron"
18
+ gem.homepage = "http://github.com/rubiojr/instalatron"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Abiquo Installer Testing Framework}
21
+ gem.description = %Q{Test graphical installers using VirtualBox plus image recognition technics}
22
+ gem.email = "srubio@abiquo.com"
23
+ gem.authors = ["Sergio Rubio"]
24
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
25
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
26
+ gem.add_runtime_dependency 'mixlib-cli', '>= 1.2'
27
+ gem.add_runtime_dependency 'mixlib-cli', '>= 1.2'
28
+ gem.add_runtime_dependency 'virtualbox', '>= 0.8'
29
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
30
+ end
31
+ Jeweler::RubygemsDotOrgTasks.new
32
+
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'instalatron'
5
+
6
+ def monitor_session(vm_name, script)
7
+ ctrlc_gap = 0
8
+ basedir = File.dirname(script)
9
+ script = YAML.load_file(script)
10
+ require 'pp'
11
+ script.each do |screen|
12
+ ref_img = "#{basedir}/#{File.basename(screen[:image])}"
13
+ print "Waiting for '#{screen[:name]}'... ".ljust(45)
14
+ loop do
15
+ begin
16
+ img = Instalatron.detect_screen(vm_name)
17
+ if Instalatron.same_image?(ref_img, img)
18
+ puts "DETECTED"
19
+ break
20
+ end
21
+ rescue Interrupt, SystemExit
22
+ if Time.now.to_f - ctrlc_gap < 0.5
23
+ puts "\n\nDouble Ctrl-c detected. Aborting."
24
+ exit
25
+ else
26
+ ctrlc_gap = Time.now.to_f
27
+ end
28
+ puts "SKIP"
29
+ break
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ $stdout.sync = true
36
+ vm_name = ARGV[0]
37
+ running_vms = []
38
+ `VBoxManage list runningvms`.each_line do |l|
39
+ vm = l.split[0].gsub('"', '')
40
+ running_vms << vm
41
+ end
42
+ if not running_vms.include?(vm_name)
43
+ $stderr.puts "Running VM #{vm_name} not found.\n\n"
44
+ $stderr.puts "Usage: instalatron-monitor <vm_name> <script>"
45
+ exit 1
46
+ end
47
+
48
+ script = ARGV[1]
49
+ if script.nil? or not File.exist?(script)
50
+ $stderr.puts "Invalid script.\n\n"
51
+ $stderr.puts "Usage: instalatron-monitor <vm_name> <script>"
52
+ exit 1
53
+ end
54
+
55
+ puts "Monitoring #{vm_name} VM\n\n"
56
+ puts "CTRL-C skipts step"
57
+ puts "Pressing CTRL-C twice aborts\n\n"
58
+ monitor_session vm_name, script
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ require 'instalatron'
4
+ require 'yaml'
5
+ require 'mixlib/cli'
6
+
7
+ def play_session(vm_name, script)
8
+ ctrlc_gap = 0
9
+ basedir = File.dirname(script)
10
+ script = YAML.load_file(script)
11
+ require 'pp'
12
+ script.each do |screen|
13
+ ref_img = "#{basedir}/#{File.basename(screen[:image])}"
14
+ loop do
15
+ begin
16
+ img = Instalatron.detect_screen(vm_name)
17
+ if Instalatron.same_image?(ref_img, img)
18
+ puts "Screen detected: #{screen[:name]}"
19
+ Instalatron.command_window screen[:sequence], vm_name
20
+ break
21
+ end
22
+ rescue Interrupt, SystemExit
23
+ if Time.now.to_f - ctrlc_gap < 0.5
24
+ puts "\n\nDouble Ctrl-c detected. Aborting."
25
+ exit
26
+ else
27
+ ctrlc_gap = Time.now.to_f
28
+ end
29
+ puts "Skipping #{screen[:name]}"
30
+ break
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def required_option(cli, opt)
37
+ if cli.config[opt].nil?
38
+ $stderr.puts "\n#{opt.to_s} argument requied.\n\n"
39
+ $stderr.puts cli.opt_parser.help
40
+ exit 1
41
+ end
42
+ return cli.config[opt]
43
+ end
44
+
45
+ def usage(cli)
46
+ $stderr.puts cli.opt_parser.help
47
+ exit 1
48
+ end
49
+
50
+ class MyCLI
51
+ include Mixlib::CLI
52
+
53
+ option :vm_name,
54
+ :short => "-n NAME",
55
+ :long => "--vm-name NAME",
56
+ :description => "Virtual Machine Name",
57
+ :default => "instalatron_#{Time.now.strftime('%s')}"
58
+
59
+ option :iso_file,
60
+ :short => "-i ISO",
61
+ :long => "--iso-file ISO",
62
+ :description => "ISO file to boot the VM with"
63
+
64
+ option :script,
65
+ :short => "-s SCRIPT",
66
+ :long => "--script SCRIPT",
67
+ :description => "Path to the script file (script.yml) or directory."
68
+
69
+ option :help,
70
+ :short => "-h",
71
+ :long => "--help",
72
+ :description => "Show this message",
73
+ :on => :tail,
74
+ :boolean => true,
75
+ :show_options => true,
76
+ :exit => 0
77
+
78
+ end
79
+
80
+ cli = MyCLI.new
81
+ cli.parse_options
82
+
83
+ vm_name = cli.config[:vm_name]
84
+
85
+ script = required_option(cli, :script)
86
+
87
+ if File.directory?(script)
88
+ script = script + '/script.yml'
89
+ end
90
+
91
+ if not File.exist?(script)
92
+ $stderr.puts "Script file script.yml not found.\n\n"
93
+ usage(cli)
94
+ end
95
+
96
+ iso_file = required_option(cli, :iso_file)
97
+ if not File.exist?(iso_file)
98
+ $stderr.puts "Invalid ISO file.\n\n"
99
+ usage(cli)
100
+ end
101
+
102
+ # Create VBox VM first
103
+ Instalatron.create_vm :vm_name => vm_name, :iso_file => iso_file
104
+
105
+ puts "Playing script using VM #{vm_name}\n\n"
106
+ play_session vm_name, script
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ require 'instalatron'
4
+ require 'yaml'
5
+
6
+ def record_session(vm_name, session_name = "instalatron_rec_" + Time.now.strftime("%F_%H%M"))
7
+ puts "Recording session #{session_name}\n\n"
8
+ script = []
9
+ $stdout.sync = true
10
+ screen_count = 1
11
+ Dir.mkdir session_name if not File.directory?(session_name)
12
+ begin
13
+ print "Press ENTER to grab screen..."
14
+ $stdin.gets
15
+ loop do
16
+ step = {}
17
+ img = Instalatron.detect_screen(vm_name)
18
+
19
+ # Get step name
20
+ puts "Screen captured\n\n"
21
+ print "Step name: "
22
+ step[:name] = $stdin.gets.strip.chomp
23
+
24
+ # Capture key sequence
25
+ print "Key sequence: "
26
+ step[:sequence] = $stdin.gets.strip.chomp
27
+ if step[:sequence].empty?
28
+ step[:sequence] = "<Enter>"
29
+ end
30
+
31
+ # Copy screenshot to session dir
32
+ step[:image] = "#{step[:name].gsub(' ','_').downcase}.png"
33
+ FileUtils.cp img, "#{session_name}/#{step[:image]}"
34
+
35
+ script << step
36
+ puts
37
+ Instalatron.command_window(step[:sequence], vm_name)
38
+ screen_count += 1
39
+ print "Press ENTER to grab screen (#{screen_count})..."
40
+ $stdin.gets
41
+ end
42
+ rescue SystemExit, Interrupt
43
+ puts "Aborting..."
44
+ File.open "#{session_name}/script.yml", 'w' do |f|
45
+ f.puts script.to_yaml
46
+ end
47
+ end
48
+ end
49
+
50
+ vm_name = ARGV[0]
51
+ running_vms = []
52
+ `VBoxManage list runningvms`.each_line do |l|
53
+ vm = l.split[0].gsub('"', '')
54
+ running_vms << vm
55
+ end
56
+ if not running_vms.include?(vm_name)
57
+ $stderr.puts "Running VM #{vm_name} not found.\n\n"
58
+
59
+ $stderr.puts "Usage: instalatron-record <vm_name> [session_name]"
60
+ exit 1
61
+ end
62
+
63
+ session_name = ARGV[1] || "instalatron_rec_" + Time.now.strftime("%F_%H%M")
64
+
65
+ record_session vm_name, session_name
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+ require 'pp'
4
+
5
+ seq = $stdin.gets.strip.chomp
6
+
7
+ chars = []
8
+ seq.each_char do |c|
9
+ chars << c
10
+ end
11
+
12
+ puts chars.to_yaml
13
+
14
+
15
+
@@ -0,0 +1,208 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+ require 'virtualbox'
4
+
5
+ module Instalatron
6
+
7
+ VERSION = '0.1'
8
+
9
+ def self.create_vm(params = {})
10
+ vm_name = params[:vm_name] || "instalatron_#{Time.now.to_f}"
11
+ full_iso_file = params[:iso_file]
12
+ if full_iso_file.nil? or not File.exist?(full_iso_file)
13
+ raise ArgumentError.new("Invalid :iso_file parameter.")
14
+ end
15
+ os_type = params[:os_type] || 'RedHat_64'
16
+ vboxcmd = params[:vboxcmd] || 'VBoxManage'
17
+ vm_memory = params[:vm_memory] || 512
18
+ vm_cpus = params[:vm_cpus] || 1
19
+ # listing os types
20
+ # VirtualBox::Global.global.lib.virtualbox.guest_os_types.each do |os|
21
+ # puts os.id
22
+ # end
23
+
24
+ # make sure the VM does not exist
25
+ vm=VirtualBox::VM.find(vm_name)
26
+
27
+ if vm.nil?
28
+ `#{vboxcmd} createvm --name '#{vm_name}' --ostype #{os_type} --register >/dev/null 2>&1`
29
+ `#{vboxcmd} modifyvm #{vm_name} --ioapic on >/dev/null 2>&1`
30
+ `#{vboxcmd} modifyvm #{vm_name} --pae on >/dev/null 2>&1`
31
+ else
32
+ exit 1
33
+ end
34
+
35
+ vm=VirtualBox::VM.find(vm_name)
36
+ vm.memory_size= vm_memory
37
+ vm.os_type_id = os_type
38
+ vm.cpu_count = vm_cpus
39
+ vm.name = vm_name
40
+
41
+ vm.boot_order[0]=:dvd
42
+ vm.boot_order[1]=:hard_disk
43
+ vm.boot_order[2]=:null
44
+ vm.boot_order[3]=:null
45
+ vm.validate
46
+ vm.save
47
+
48
+ # Create DISK
49
+ place = `#{vboxcmd} list systemproperties|grep '^Default machine'|cut -d ':' -f 2|sed -e 's/^[ ]*//'`.strip.chomp
50
+ disk_file = "#{place}/#{vm_name}/#{vm_name}.vdi"
51
+
52
+ `#{vboxcmd} createhd --filename '#{disk_file}' --size 8192 --format VDI >/dev/null 2>&1`
53
+
54
+ # Add IDE/Sata Controllers
55
+ `#{vboxcmd} storagectl '#{vm_name}' --name 'SATA Controller' --add sata --hostiocache off >/dev/null 2>&1`
56
+ `#{vboxcmd} storagectl '#{vm_name}' --name 'IDE Controller' --add ide >/dev/null 2>&1`
57
+
58
+ # Attach disk
59
+ `#{vboxcmd} storageattach '#{vm_name}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '#{disk_file}' >/dev/null 2>&1`
60
+
61
+ `#{vboxcmd} storageattach '#{vm_name}' --storagectl 'IDE Controller' --type dvddrive --port 1 --device 0 --medium '#{full_iso_file}' >/dev/null 2>&1`
62
+
63
+ vm.start
64
+ end
65
+
66
+ def self.command_window(seq, vm_name, key_press_delay = 0)
67
+ if seq.is_a? String
68
+ seq = [seq]
69
+ end
70
+ seq.each do |str|
71
+ keycodes = string_to_keycode str
72
+ keycodes.split.each do |k|
73
+ `VBoxManage controlvm #{vm_name} keyboardputscancode '#{k}' >/dev/null 2>&1`
74
+ end
75
+ #sleep key_press_delay
76
+ end
77
+ end
78
+
79
+ def self.grab_screenshot(vm_name, dest_file = nil)
80
+ if dest_file.nil?
81
+ dest_file = vm_name + "_#{Time.now.to_f}.png"
82
+ end
83
+ `VBoxManage controlvm #{vm_name} screenshotpng #{dest_file} >/dev/null 2>&1`
84
+ end
85
+
86
+ def self.same_image?(ref_image, new_img, threshold = 1500)
87
+ `file #{ref_image}` =~ /(\d+\sx\s\d+)/
88
+ geom1 = $1
89
+ `file #{new_img}` =~ /(\d+\sx\s\d+)/
90
+ geom2 = $1
91
+
92
+ # geometries are different
93
+ return false if geom1 != geom2
94
+
95
+ tmp_img = "/tmp/diff_#{Time.now.to_f}.png"
96
+ metric = `compare -metric RMSE #{ref_image} #{new_img} #{tmp_img} 2>&1`.strip.chomp.split[0].to_i
97
+ FileUtils.rm tmp_img if File.exist?(tmp_img)
98
+ if metric < threshold
99
+ return true
100
+ end
101
+ false
102
+ end
103
+
104
+ def self.detect_screen(vm_name)
105
+ new_img = '/tmp/' + vm_name + '_new.png'
106
+ old_img = '/tmp/' + vm_name + '_old.png'
107
+ loop do
108
+ grab_screenshot(vm_name, old_img)
109
+ sleep 0.5
110
+ grab_screenshot(vm_name, new_img)
111
+ break if same_image?(old_img, new_img)
112
+ end
113
+ new_img
114
+ end
115
+
116
+ def self.string_to_keycode(thestring)
117
+ k=Hash.new
118
+ k['1'] = '02 82'
119
+ k['2'] = '03 83'
120
+ k['3'] = '04 84'
121
+ k['4'] = '05 85'
122
+ k['5'] = '06 86'
123
+ k['6'] = '07 87'
124
+ k['7'] = '08 88'
125
+ k['8'] = '09 89'
126
+ k['9'] = '0a 8a'
127
+ k['0'] = '0b 8b'
128
+ k['-'] = '0c 8c'
129
+ k['='] = '0d 8d'
130
+ k['Tab'] = '0f 8f';
131
+ k['q'] = '10 90' ; k['w'] = '11 91' ; k['e'] = '12 92';
132
+ k['r'] = '13 93' ; k['t'] = '14 94' ; k['y'] = '15 95';
133
+ k['u']= '16 96' ; k['i']='17 97'; k['o'] = '18 98' ; k['p'] = '19 99' ;
134
+
135
+ k['Q'] = '2a 10 aa' ; k['W'] = '2a 11 aa' ; k['E'] = '2a 12 aa'; k['R'] = '2a 13 aa' ; k['T'] = '2a 14 aa' ; k['Y'] = '2a 15 aa'; k['U']= '2a 16 aa' ; k['I']='2a 17 aa'; k['O'] = '2a 18 aa' ; k['P'] = '2a 19 aa' ;
136
+
137
+ k['a'] = '1e 9e'; k['s'] = '1f 9f' ; k['d'] = '20 a0' ; k['f'] = '21 a1'; k['g'] = '22 a2' ; k['h'] = '23 a3' ; k['j'] = '24 a4';
138
+ k['k']= '25 a5' ; k['l']='26 a6';
139
+ k['A'] = '2a 1e aa 9e'; k['S'] = '2a 1f aa 9f' ; k['D'] = '2a 20 aa a0' ; k['F'] = '2a 21 aa a1';
140
+ k['G'] = '2a 22 aa a2' ; k['H'] = '2a 23 aa a3' ; k['J'] = '2a 24 aa a4'; k['K']= '2a 25 aa a5' ; k['L']='2a 26 aa a6';
141
+
142
+ k[';'] = '27 a7' ;k['"']='2a 28 aa a8';k['\'']='28 a8';
143
+
144
+ k['\\'] = '2b ab'; k['|'] = '2a 2b aa 8b';
145
+
146
+ k['[']='1a 9a'; k[']']='1b 9b';
147
+ k['<']='2a 33 aa b3'; k['>']='2a 34 aa b4';
148
+ k['$']='2a 05 aa 85';
149
+ k['+']='2a 0d aa 8d';
150
+
151
+ k['z'] = '2c ac'; k['x'] = '2d ad' ; k['c'] = '2e ae' ; k['v'] = '2f af'; k['b'] = '30 b0' ; k['n'] = '31 b1' ;
152
+ k['m'] = '32 b2';
153
+ k['Z'] = '2a 2c aa ac'; k['X'] = '2a 2d aa ad' ; k['C'] = '2a 2e aa ae' ; k['V'] = '2a 2f aa af';
154
+ k['B'] = '2a 30 aa b0' ; k['N'] = '2a 31 aa b1' ; k['M'] = '2a 32 aa b2';
155
+
156
+ k[',']= '33 b3' ; k['.']='34 b4'; k['/'] = '35 b5' ;k[':'] = '2a 27 aa a7';
157
+ k['%'] = '2a 06 aa 86'; k['_'] = '2a 0c aa 8c';
158
+ k['&'] = '2a 08 aa 88';
159
+ k['('] = '2a 0a aa 8a';
160
+ k[')'] = '2a 0b aa 8b';
161
+
162
+
163
+ special=Hash.new;
164
+ special['<Enter>'] = '1c 9c';
165
+ special['<Backspace>'] = '0e 8e';
166
+ special['<Spacebar>'] = '39 b9';
167
+ special['<Return>'] = '1c 9c'
168
+ special['<Esc>'] = '01 81';
169
+ special['<Tab>'] = '0f 8f';
170
+ special['<KillX>'] = '1d 38 0e';
171
+ special['<Wait>'] = 'wait';
172
+
173
+ special['<Up>'] = '48 c8';
174
+ special['<Down>'] = '50 d0';
175
+ #special['<PageUp>'] = '01';
176
+ #special['<PageDown>'] = '01';
177
+
178
+ keycodes=''
179
+ thestring.gsub!(/ /,"<Spacebar>")
180
+
181
+ until thestring.length == 0
182
+ nospecial=true;
183
+ special.keys.each { |key|
184
+ if thestring =~ /^#{key}.*/i
185
+ #take thestring
186
+ #check if it starts with a special key + pop special string
187
+ keycodes=keycodes+special[key]+' ';
188
+ thestring=thestring.slice(key.length,thestring.length-key.length)
189
+ nospecial=false;
190
+ break;
191
+ end
192
+ }
193
+ if nospecial
194
+ code=k[thestring.slice(0,1)]
195
+ if !code.nil?
196
+ keycodes=keycodes+code+' '
197
+ else
198
+ puts "no scan code for #{thestring.slice(0,1)}"
199
+ end
200
+ #pop one
201
+ thestring=thestring.slice(1,thestring.length-1)
202
+ end
203
+ end
204
+
205
+ return keycodes
206
+ end
207
+
208
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: instalatron
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Sergio Rubio
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-08 00:00:00 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ requirement: &id001 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ~>
24
+ - !ruby/object:Gem::Version
25
+ hash: 23
26
+ segments:
27
+ - 1
28
+ - 0
29
+ - 0
30
+ version: 1.0.0
31
+ version_requirements: *id001
32
+ name: bundler
33
+ prerelease: false
34
+ type: :development
35
+ - !ruby/object:Gem::Dependency
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ hash: 7
42
+ segments:
43
+ - 1
44
+ - 5
45
+ - 2
46
+ version: 1.5.2
47
+ version_requirements: *id002
48
+ name: jeweler
49
+ prerelease: false
50
+ type: :development
51
+ - !ruby/object:Gem::Dependency
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 11
58
+ segments:
59
+ - 1
60
+ - 2
61
+ version: "1.2"
62
+ version_requirements: *id003
63
+ name: mixlib-cli
64
+ prerelease: false
65
+ type: :runtime
66
+ - !ruby/object:Gem::Dependency
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 11
73
+ segments:
74
+ - 1
75
+ - 2
76
+ version: "1.2"
77
+ version_requirements: *id004
78
+ name: mixlib-cli
79
+ prerelease: false
80
+ type: :runtime
81
+ - !ruby/object:Gem::Dependency
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 27
88
+ segments:
89
+ - 0
90
+ - 8
91
+ version: "0.8"
92
+ version_requirements: *id005
93
+ name: virtualbox
94
+ prerelease: false
95
+ type: :runtime
96
+ description: Test graphical installers using VirtualBox plus image recognition technics
97
+ email: srubio@abiquo.com
98
+ executables:
99
+ - print-yaml-keyseq
100
+ - instalatron-record
101
+ - instalatron-play
102
+ - instalatron-monitor
103
+ extensions: []
104
+
105
+ extra_rdoc_files:
106
+ - LICENSE.txt
107
+ - README.rdoc
108
+ files:
109
+ - .document
110
+ - Gemfile
111
+ - LICENSE.txt
112
+ - README.rdoc
113
+ - Rakefile
114
+ - bin/instalatron-monitor
115
+ - bin/instalatron-play
116
+ - bin/instalatron-record
117
+ - bin/print-yaml-keyseq
118
+ - lib/instalatron.rb
119
+ homepage: http://github.com/rubiojr/instalatron
120
+ licenses:
121
+ - MIT
122
+ post_install_message:
123
+ rdoc_options: []
124
+
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ hash: 3
142
+ segments:
143
+ - 0
144
+ version: "0"
145
+ requirements: []
146
+
147
+ rubyforge_project:
148
+ rubygems_version: 1.7.2
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: Abiquo Installer Testing Framework
152
+ test_files: []
153
+