virtualbox-com 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/Gemfile +9 -0
- data/LICENSE +19 -0
- data/Rakefile +8 -0
- data/Readme.md +59 -0
- data/examples/simple.rb +43 -0
- data/lib/virtualbox-com.rb +1 -0
- data/lib/virtualbox/com.rb +51 -0
- data/lib/virtualbox/com/abstract_enum.rb +51 -0
- data/lib/virtualbox/com/abstract_interface.rb +144 -0
- data/lib/virtualbox/com/abstract_model.rb +14 -0
- data/lib/virtualbox/com/exceptions.rb +32 -0
- data/lib/virtualbox/com/iid.rb +43 -0
- data/lib/virtualbox/com/model/4.2-gen.rb +2720 -0
- data/lib/virtualbox/com/model/4.2.rb +97 -0
- data/lib/virtualbox/com/util.rb +119 -0
- data/lib/virtualbox/com/version.rb +5 -0
- data/lib/virtualbox/com/xpcomc-ffi.rb +76 -0
- data/lib/virtualbox/com/xpcomc-ffi/binding.rb +87 -0
- data/lib/virtualbox/com/xpcomc-ffi/implementer.rb +86 -0
- data/lib/virtualbox/com/xpcomc-ffi/lib.rb +90 -0
- data/lib/virtualbox/com/xpcomc-ffi/model-types.rb +15 -0
- data/lib/virtualbox/com/xpcomc-ffi/sig.rb +342 -0
- data/lib/virtualbox/com/xpcomc-ffi/spec.rb +58 -0
- data/lib/virtualbox/com/xpcomc-ffi/xpcomc-vbox.rb +54 -0
- data/scripts/xidl-conv.rb +124 -0
- data/virtualbox-com.gemspec +27 -0
- metadata +123 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010 Mitchell Hashimoto.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# VirtualBox-Com Ruby Gem
|
2
|
+
|
3
|
+
This is a simplified version of the unmaintained virtualbox gem
|
4
|
+
by [Mitchell Hashimoto](https://github.com/mitchellh)
|
5
|
+
|
6
|
+
The VirtualBox::COM ruby gem is a library which allows anyone to control
|
7
|
+
VirtualBox from ruby code! Create, destroy, start, stop, suspend, and
|
8
|
+
resume virtual machines. Also list virtual machines, list hard
|
9
|
+
drives, network devices, etc.
|
10
|
+
|
11
|
+
## Installation and Requirements
|
12
|
+
|
13
|
+
First you need to install [VirtualBox](http://www.virtualbox.org/)
|
14
|
+
which is available for Windows, Linux, and OS X. After installation,
|
15
|
+
install the gem:
|
16
|
+
|
17
|
+
sudo gem install virtualbox-com
|
18
|
+
|
19
|
+
The gem uses the native COM interface with VirtualBox provides to
|
20
|
+
communicate with VirtualBox. The gem uses Ruby-FFI to talk to a
|
21
|
+
dynamic library. No configuration should be necessary.
|
22
|
+
|
23
|
+
## Basic Usage
|
24
|
+
|
25
|
+
require 'virtualbox-com'
|
26
|
+
|
27
|
+
lib = VirtualBox::COM
|
28
|
+
|
29
|
+
puts lib.virtualbox.machines[0].name
|
30
|
+
puts lib.virtualbox.find_machine('Windows').groups
|
31
|
+
|
32
|
+
## Known Issues or Uncompleted Features
|
33
|
+
|
34
|
+
All the classes are generated from the VirtualBox.xidl
|
35
|
+
|
36
|
+
## Reporting Bugs or Feature Requests
|
37
|
+
|
38
|
+
Please use the [issue tracker](https://github.com/sdalu/virtualbox-com/issues).
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
If you'd like to contribute to VirtualBox, the first step to developing is to
|
43
|
+
clone this repo, get [bundler](http://github.com/carlhuda/bundler) if you
|
44
|
+
don't have it already, and do the following:
|
45
|
+
|
46
|
+
bundle install --relock
|
47
|
+
rake
|
48
|
+
|
49
|
+
This will run the test suite, which should come back all green! Then
|
50
|
+
you're good to go!
|
51
|
+
|
52
|
+
## Special Thanks
|
53
|
+
|
54
|
+
These folks went above and beyond with contributions to the virtualbox gem, and
|
55
|
+
for that, I have to say "thanks!"
|
56
|
+
|
57
|
+
* [Mitchell Hashimoto](https://github.com/mitchellh)
|
58
|
+
* [Kieran Pilkington](https://github.com/KieranP)
|
59
|
+
* [Aleksey Palazhchenko](https://github.com/AlekSi)
|
data/examples/simple.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'virtualbox-com'
|
3
|
+
|
4
|
+
# Shortcut
|
5
|
+
lib = VirtualBox::COM
|
6
|
+
|
7
|
+
# Name of the first VM
|
8
|
+
puts lib.virtualbox.machines[0].name
|
9
|
+
|
10
|
+
# Groups of the VM named 'Windows'
|
11
|
+
puts lib.virtualbox.find_machine('Windows').groups
|
12
|
+
|
13
|
+
# Register a passive listener
|
14
|
+
begin
|
15
|
+
s = VirtualBox::COM.virtualbox.event_source
|
16
|
+
l = s.create_listener
|
17
|
+
# Listen on all events with a passive listener
|
18
|
+
s.register_listener(l, [ :any ], false)
|
19
|
+
while true do
|
20
|
+
# Get event
|
21
|
+
if e = s.get_event(l, 1000)
|
22
|
+
case e.type
|
23
|
+
when :on_guest_property_changed
|
24
|
+
# If GuestProperyChanged cast the event to the
|
25
|
+
# model having the most information
|
26
|
+
n = e.cast(:GuestPropertyChangedEvent)
|
27
|
+
puts "GuestProperty: #{n.machine_id} / #{n.name} / #{n.value}"
|
28
|
+
else
|
29
|
+
# Display event type
|
30
|
+
puts "Event: #{e.type}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# If event is waitable, acknowlege we have finished with it
|
34
|
+
if e.waitable
|
35
|
+
e.source.event_processed(l, e)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
rescue VirtualBox::COM::ObjectNotFoundException
|
40
|
+
# Could just be because we weren't able to collect data fast
|
41
|
+
# enough, so VirtualBox unregistered our listener
|
42
|
+
retry
|
43
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'virtualbox/com.rb'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module COM
|
3
|
+
# Versions of Virtualbox that are supported
|
4
|
+
SUPPORTED_VERSIONS = {
|
5
|
+
"4.2" => [ "3b2f08eb-b810-4715-bee0-bb06b9880ad2",
|
6
|
+
"12f4dcdb-12b2-4ec1-b7cd-ddd9f6c5bf4d" ],
|
7
|
+
}
|
8
|
+
|
9
|
+
# The Model module will hold all the model descriptions that will
|
10
|
+
# be loaded according to the VirtualBox version
|
11
|
+
module Model
|
12
|
+
def self.get(name)
|
13
|
+
self.const_get(name, false)
|
14
|
+
rescue NameError
|
15
|
+
raise ModelNotFoundException, name
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.create(name, *args)
|
19
|
+
self.get(name).new(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Information about VirtualBox version
|
24
|
+
def self.supported? ; !version.nil? ; end
|
25
|
+
def self.version ; virtualbox.version_normalized rescue nil ; end
|
26
|
+
def self.revision ; virtualbox.revision.to_s rescue nil ; end
|
27
|
+
|
28
|
+
# Helpers for inclusion
|
29
|
+
def virtualbox ; COM.virtualbox ; end
|
30
|
+
def session ; COM.session ; end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# Exceptions
|
36
|
+
require_relative 'com/exceptions'
|
37
|
+
|
38
|
+
# Abstract class for model definitions
|
39
|
+
require_relative 'com/abstract_enum'
|
40
|
+
require_relative 'com/abstract_interface'
|
41
|
+
|
42
|
+
# Classes
|
43
|
+
require_relative 'com/iid'
|
44
|
+
|
45
|
+
# Implementation
|
46
|
+
# It needs to add the following to VirtualBox::COM
|
47
|
+
# - Methods: virtualbox, session
|
48
|
+
# - Class : Implementer
|
49
|
+
# - Types : INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64,
|
50
|
+
# WSTRING, BOOL
|
51
|
+
require_relative 'com/xpcomc-ffi'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative "abstract_model"
|
2
|
+
|
3
|
+
module VirtualBox
|
4
|
+
module COM
|
5
|
+
|
6
|
+
# Represents a C enum type. Provides functionality to easily convert
|
7
|
+
# an int value to its proper symbol within the enum.
|
8
|
+
class AbstractEnum < AbstractModel
|
9
|
+
extend Enumerable
|
10
|
+
|
11
|
+
# Defines the mapping of int => symbol for the given Enum.
|
12
|
+
# The parameter to this can be an Array or Hash or anything which
|
13
|
+
# respond to `each` and yield a key/value pair.
|
14
|
+
# If a value appear more than once, only the first is kept
|
15
|
+
# If value is left nil, it will return the current mapping
|
16
|
+
def self.map(value = nil)
|
17
|
+
if value
|
18
|
+
m, r = {}, {}
|
19
|
+
if Array === value
|
20
|
+
then value.each_index {|i| m[value[i]] = i; r[i] = value[i] }
|
21
|
+
else value.each {|k,v| m[k] = v; r[v] ||= k }
|
22
|
+
end
|
23
|
+
@map, @reverse_map = m, r
|
24
|
+
end
|
25
|
+
|
26
|
+
@map
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the symbol associated with the given key
|
30
|
+
def self.[](index)
|
31
|
+
case index
|
32
|
+
when Symbol then @map[index]
|
33
|
+
else @reverse_map[index]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the index associated with a value
|
38
|
+
def self.index(key)
|
39
|
+
@map[key]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Iterate over the enum, yielding each item to a block.
|
43
|
+
def self.each
|
44
|
+
@map.each do |key, value|
|
45
|
+
yield key
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require_relative "abstract_model"
|
2
|
+
|
3
|
+
module VirtualBox
|
4
|
+
module COM
|
5
|
+
|
6
|
+
#
|
7
|
+
# # Defining an Interface
|
8
|
+
#
|
9
|
+
# Defining an interface is done by subclassing AbstractInterface and
|
10
|
+
# using the provided class methods to define the COM methods and
|
11
|
+
# properties. A small example class is shown below:
|
12
|
+
#
|
13
|
+
# class Time < AbstractInterface
|
14
|
+
# function :now, [[:out, :uint]]
|
15
|
+
# property :hour, :uint
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # Accessing an Interface
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# # Assume `time` was retrieved already
|
22
|
+
# puts time.foo.to_s
|
23
|
+
# time.hour = 20
|
24
|
+
# x = time.now
|
25
|
+
#
|
26
|
+
# The above example shows how the properties and functions can be used
|
27
|
+
# with a given interface.
|
28
|
+
#
|
29
|
+
class AbstractInterface < AbstractModel
|
30
|
+
attr_reader :implementer
|
31
|
+
|
32
|
+
class << self
|
33
|
+
|
34
|
+
# Extends the current model with another one.
|
35
|
+
# Note that redefining functions or properties is not supported.
|
36
|
+
def extends(model)
|
37
|
+
Model.get(model).members.each do |spec|
|
38
|
+
if h.include?(spec.name)
|
39
|
+
raise "redefining of #{spec.name} is not supported"
|
40
|
+
end
|
41
|
+
h[spec.name] = spec
|
42
|
+
end
|
43
|
+
rescue ModelNotFoundException
|
44
|
+
raise "trying to extend an unknown model (#{model})"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Adds a function to the interface
|
48
|
+
def function(name, type, args, opts={})
|
49
|
+
h[name] = Spec::Function.new(name, type, args, opts)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Adds a property to the interface
|
53
|
+
def property(name, type, opts={})
|
54
|
+
h[name] = Spec::Property.new(name, type, opts)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Perform final setup
|
58
|
+
def setup
|
59
|
+
members.each {|spec| name = spec.name
|
60
|
+
case spec
|
61
|
+
when Spec::Function
|
62
|
+
define_method(name) { |*args|
|
63
|
+
@implementer.call_function(spec, *args)
|
64
|
+
} unless spec.hide?
|
65
|
+
when Spec::Property
|
66
|
+
define_method(name) {
|
67
|
+
@implementer.read_property(spec)
|
68
|
+
} unless spec.hide?
|
69
|
+
define_method(:"#{name}=") { |value|
|
70
|
+
@implementer.write_property(spec, value)
|
71
|
+
} unless spec.hide? || spec.readonly?
|
72
|
+
end
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get a member by name
|
77
|
+
def member(name)
|
78
|
+
h[name]
|
79
|
+
end
|
80
|
+
|
81
|
+
# List of members (Spec::*)
|
82
|
+
def members
|
83
|
+
h.values
|
84
|
+
end
|
85
|
+
|
86
|
+
# List of functions (Spec::Function)
|
87
|
+
def functions
|
88
|
+
members.select {|s| s.kind_of?(Spec::Function) }
|
89
|
+
end
|
90
|
+
|
91
|
+
# List if properties (Spec::Property)
|
92
|
+
def properties
|
93
|
+
members.select {|s| s.kind_of?(Spec::Property) }
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
private
|
98
|
+
def h ; @h ||= {} ; end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# Initializes the interface with the given implementer
|
103
|
+
def initialize(*args)
|
104
|
+
@args = args
|
105
|
+
@implementer = Implementer.new(self, *args)
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
# Cast to another model
|
110
|
+
def cast(name)
|
111
|
+
@implementer.cast(name, *@args)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Reads a property with the given name
|
115
|
+
def read_property(name)
|
116
|
+
spec = self.class.member(name)
|
117
|
+
raise "#{name} is not a property" unless spec.kind_of?(Spec::Property)
|
118
|
+
@implementer.read_property(spec)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Writes a property with the given name
|
122
|
+
def write_property(name, value)
|
123
|
+
spec = self.class.member(name)
|
124
|
+
raise "#{name} is not a property" unless spec.kind_of?(Spec::Property)
|
125
|
+
raise "property #{name} is readonly" if spec.readonly?
|
126
|
+
@implementer.write_property(spec, value)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Calls a function with the given name
|
130
|
+
def call_function(name, *args)
|
131
|
+
spec = self.class.member(name)
|
132
|
+
raise "#{name} is not a function" unless spec.kind_of?(Spec::Function)
|
133
|
+
@implementer.call_function(spec, args)
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
# Concise inspect
|
138
|
+
def inspect
|
139
|
+
"#<#{self.class.name}>"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module COM
|
3
|
+
|
4
|
+
class ModelNotFoundException < ::Exception; end
|
5
|
+
|
6
|
+
class COMException < ::Exception
|
7
|
+
attr_accessor :data
|
8
|
+
|
9
|
+
def initialize(data={})
|
10
|
+
@data = data
|
11
|
+
super("Error in API call to #{data[:function]}: #{data[:code]}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class NotImplementedException < COMException; end
|
16
|
+
class ObjectNotFoundException < COMException; end
|
17
|
+
class InvalidVMStateException < COMException; end
|
18
|
+
class VMErrorException < COMException; end
|
19
|
+
class FileErrorException < COMException; end
|
20
|
+
class SubsystemException < COMException; end
|
21
|
+
class PDMException < COMException; end
|
22
|
+
class InvalidObjectStateException < COMException; end
|
23
|
+
class HostErrorException < COMException; end
|
24
|
+
class NotSupportedException < COMException; end
|
25
|
+
class XMLErrorException < COMException; end
|
26
|
+
class InvalidSessionStateException < COMException; end
|
27
|
+
class ObjectInUseException < COMException; end
|
28
|
+
class InvalidArgException < COMException; end
|
29
|
+
class NoInterfaceException < COMException; end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|