boxgrinder-core 0.0.1
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.
- data/lib/boxgrinder-core.rb +1 -0
- data/lib/boxgrinder-core/defaults.rb +109 -0
- data/lib/boxgrinder-core/helpers/appliance-config-helper.rb +208 -0
- data/lib/boxgrinder-core/helpers/exec-helper.rb +46 -0
- data/lib/boxgrinder-core/helpers/log-helper.rb +61 -0
- data/lib/boxgrinder-core/models/appliance-config.rb +174 -0
- data/lib/boxgrinder-core/models/config.rb +57 -0
- data/lib/boxgrinder-core/models/task.rb +35 -0
- data/lib/boxgrinder-core/validators/appliance-definition-validator.rb +90 -0
- data/lib/boxgrinder-core/validators/errors.rb +35 -0
- metadata +71 -0
@@ -0,0 +1 @@
|
|
1
|
+
require 'boxgrinder-core/defaults'
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
module BoxGrinder
|
22
|
+
# here are global variables
|
23
|
+
SUPPORTED_ARCHES = [ "i386", "x86_64" ]
|
24
|
+
SUPPORTED_OSES = {
|
25
|
+
"fedora" => [ "12", "11", "rawhide" ]
|
26
|
+
}
|
27
|
+
|
28
|
+
LATEST_STABLE_RELEASES = {
|
29
|
+
"fedora" => "12",
|
30
|
+
"rhel" => "5"
|
31
|
+
}
|
32
|
+
|
33
|
+
DEVELOPMENT_RELEASES = {
|
34
|
+
"fedora" => "rawhide"
|
35
|
+
}
|
36
|
+
|
37
|
+
APPLIANCE_DEFAULTS = {
|
38
|
+
:os => {
|
39
|
+
:name => "fedora",
|
40
|
+
:version => LATEST_STABLE_RELEASES['fedora'],
|
41
|
+
:password => "boxgrinder"
|
42
|
+
},
|
43
|
+
:hardware => {
|
44
|
+
:partition => 1,
|
45
|
+
:memory => 256,
|
46
|
+
:network => "NAT",
|
47
|
+
:cpus => 1
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
SUPPORTED_DESKTOP_TYPES = [ "gnome" ]
|
52
|
+
|
53
|
+
# you can use #ARCH# variable to specify build arch
|
54
|
+
REPOS = {
|
55
|
+
"fedora" => {
|
56
|
+
"12" => {
|
57
|
+
"base" => {
|
58
|
+
"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-12&arch=#ARCH#"
|
59
|
+
},
|
60
|
+
"updates" => {
|
61
|
+
"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f12&arch=#ARCH#"
|
62
|
+
}
|
63
|
+
},
|
64
|
+
"11" => {
|
65
|
+
"base" => {
|
66
|
+
"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-11&arch=#ARCH#"
|
67
|
+
},
|
68
|
+
"updates" => {
|
69
|
+
"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f11&arch=#ARCH#"
|
70
|
+
}
|
71
|
+
},
|
72
|
+
"rawhide" => {
|
73
|
+
"base" => {
|
74
|
+
"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=rawhide&arch=#ARCH#"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
DEFAULT_LOCATION = {
|
81
|
+
:log => 'log/boxgrinder.log'
|
82
|
+
}
|
83
|
+
|
84
|
+
DEFAULT_HELP_TEXT = {
|
85
|
+
:general => "See documentation: http://community.jboss.org/docs/DOC-14358."
|
86
|
+
}
|
87
|
+
|
88
|
+
DEFAULT_PROJECT_CONFIG = {
|
89
|
+
:name => 'BoxGrinder',
|
90
|
+
:version => '1.0.0.Beta2',
|
91
|
+
:release => 'SNAPSHOT',
|
92
|
+
:dir_build => 'build',
|
93
|
+
#:topdir => "#{self.} build/topdir",
|
94
|
+
:dir_src_cache => 'sources-cache',
|
95
|
+
:dir_rpms_cache => 'rpms-cache',
|
96
|
+
:dir_specs => 'specs',
|
97
|
+
:dir_appliances => 'appliances',
|
98
|
+
:dir_src => 'src',
|
99
|
+
:dir_kickstarts => 'kickstarts'
|
100
|
+
}
|
101
|
+
|
102
|
+
AWS_DEFAULTS = {
|
103
|
+
:bucket_prefix => "#{DEFAULT_PROJECT_CONFIG[:name].downcase}/#{DEFAULT_PROJECT_CONFIG[:version]}-#{DEFAULT_PROJECT_CONFIG[:release]}",
|
104
|
+
:kernel_id => { "i386" => "aki-a71cf9ce", "x86_64" => "aki-b51cf9dc" }, # EU: :kernel_id => { "i386" => "aki-61022915", "x86_64" => "aki-6d022919" },
|
105
|
+
:ramdisk_id => { "i386" => "ari-a51cf9cc", "x86_64" => "ari-b31cf9da" }, # EU: :ramdisk_id => { "i386" => "ari-63022917", "x86_64" => "ari-37022943" },
|
106
|
+
:kernel_rpm => { "i386" => "http://repo.oddthesis.org/packages/other/kernel-xen-2.6.21.7-2.fc8.i686.rpm", "x86_64" => "http://repo.oddthesis.org/packages/other/kernel-xen-2.6.21.7-2.fc8.x86_64.rpm" },
|
107
|
+
:modules => { "i386" => "http://s3.amazonaws.com/ec2-downloads/ec2-modules-2.6.21.7-2.ec2.v1.2.fc8xen-i686.tgz", "x86_64" => "http://s3.amazonaws.com/ec2-downloads/ec2-modules-2.6.21.7-2.ec2.v1.2.fc8xen-x86_64.tgz" }
|
108
|
+
}
|
109
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
require 'boxgrinder-core/validators/errors'
|
22
|
+
|
23
|
+
module BoxGrinder
|
24
|
+
class ApplianceConfigHelper
|
25
|
+
|
26
|
+
def initialize( appliance_definitions )
|
27
|
+
@appliance_definitions = appliance_definitions
|
28
|
+
end
|
29
|
+
|
30
|
+
def merge( appliance_config )
|
31
|
+
@appliance_config = appliance_config
|
32
|
+
|
33
|
+
# add current appliance definition
|
34
|
+
@appliance_definitions[@appliance_config.name] = @appliance_config.definition unless @appliance_definitions.has_key?( @appliance_config.name )
|
35
|
+
|
36
|
+
@current_appliances = get_appliances( @appliance_config.name ).reverse
|
37
|
+
|
38
|
+
prepare_os
|
39
|
+
prepare_appliances
|
40
|
+
prepare_version_and_release
|
41
|
+
|
42
|
+
merge_hardware
|
43
|
+
merge_repos
|
44
|
+
merge_packages
|
45
|
+
merge_post_operations
|
46
|
+
|
47
|
+
@appliance_config
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def merge_hardware
|
53
|
+
merge_cpus
|
54
|
+
merge_partitions
|
55
|
+
merge_memory
|
56
|
+
end
|
57
|
+
|
58
|
+
def merge_cpus
|
59
|
+
unless @appliance_config.definition['hardware'].nil? or @appliance_config.definition['hardware']['cpus'].nil?
|
60
|
+
@appliance_config.hardware.cpus = @appliance_config.definition['hardware']['cpus']
|
61
|
+
end
|
62
|
+
|
63
|
+
merge_field('cpus', 'hardware'){ |cpus| @appliance_config.hardware.cpus = cpus if cpus > @appliance_config.hardware.cpus }
|
64
|
+
|
65
|
+
@appliance_config.hardware.cpus = APPLIANCE_DEFAULTS[:hardware][:cpus] if @appliance_config.hardware.cpus == 0
|
66
|
+
end
|
67
|
+
|
68
|
+
# This will merge partitions from multiple appliances.
|
69
|
+
def merge_partitions
|
70
|
+
partitions = {}
|
71
|
+
|
72
|
+
unless @appliance_config.definition['hardware'].nil? or @appliance_config.definition['hardware']['partitions'].nil?
|
73
|
+
for partition in @appliance_config.definition['hardware']['partitions']
|
74
|
+
partitions[partition['root']] = partition
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
partitions['/'] = { 'root' => '/', 'size' => APPLIANCE_DEFAULTS[:hardware][:partition] } unless partitions.keys.include?('/')
|
79
|
+
|
80
|
+
merge_field('partitions', 'hardware') do |parts|
|
81
|
+
for partition in parts
|
82
|
+
if partitions.keys.include?(partition['root'])
|
83
|
+
partitions[partition['root']]['size'] = partition['size'] if partitions[partition['root']]['size'] < partition['size']
|
84
|
+
else
|
85
|
+
partitions[partition['root']] = partition
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
@appliance_config.hardware.partitions = partitions
|
91
|
+
end
|
92
|
+
|
93
|
+
def merge_memory
|
94
|
+
@appliance_config.hardware.memory = @appliance_config.definition['hardware']['memory'] unless @appliance_config.definition['hardware'].nil? or @appliance_config.definition['hardware']['memory'].nil?
|
95
|
+
|
96
|
+
merge_field('memory', 'hardware') { |memory| @appliance_config.hardware.memory = memory if memory > @appliance_config.hardware.memory }
|
97
|
+
|
98
|
+
@appliance_config.hardware.memory = APPLIANCE_DEFAULTS[:hardware][:memory] if @appliance_config.hardware.memory == 0
|
99
|
+
end
|
100
|
+
|
101
|
+
def prepare_os
|
102
|
+
merge_field( 'name', 'os' ) { |name| @appliance_config.os.name = name.to_s }
|
103
|
+
merge_field( 'version', 'os' ) { |version| @appliance_config.os.version = version.to_s }
|
104
|
+
merge_field( 'password', 'os' ) { |password| @appliance_config.os.password = password.to_s }
|
105
|
+
end
|
106
|
+
|
107
|
+
def prepare_appliances
|
108
|
+
for appliance in @current_appliances
|
109
|
+
@appliance_config.appliances << appliance
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def prepare_version_and_release
|
114
|
+
unless @appliance_config.definition['version'].nil?
|
115
|
+
@appliance_config.version = @appliance_config.definition['version']
|
116
|
+
end
|
117
|
+
|
118
|
+
unless @appliance_config.definition['release'].nil?
|
119
|
+
@appliance_config.release = @appliance_config.definition['release']
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def merge_repos
|
124
|
+
for appliance_name in @current_appliances
|
125
|
+
definition = @appliance_definitions[appliance_name]
|
126
|
+
|
127
|
+
for repo in definition['repos']
|
128
|
+
repo['name'] = substitute_repo_parameters( repo['name'] )
|
129
|
+
['baseurl', 'mirrorlist'].each do |type|
|
130
|
+
repo[type] = substitute_repo_parameters( repo[type] ) unless repo[type].nil?
|
131
|
+
end
|
132
|
+
|
133
|
+
@appliance_config.repos << repo
|
134
|
+
end unless definition['repos'].nil?
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def substitute_repo_parameters( str )
|
139
|
+
return if str.nil?
|
140
|
+
str.gsub( /#OS_NAME#/, @appliance_config.os.name ).gsub( /#OS_VERSION#/, @appliance_config.os.version ).gsub( /#ARCH#/, @appliance_config.hardware.arch )
|
141
|
+
end
|
142
|
+
|
143
|
+
def merge_packages
|
144
|
+
for appliance_name in @current_appliances
|
145
|
+
definition = @appliance_definitions[appliance_name]
|
146
|
+
|
147
|
+
unless definition['packages'].nil?
|
148
|
+
for package in definition['packages']['includes']
|
149
|
+
@appliance_config.packages << package
|
150
|
+
end unless definition['packages']['includes'].nil?
|
151
|
+
|
152
|
+
for package in definition['packages']['excludes']
|
153
|
+
@appliance_config.packages << "-#{package}"
|
154
|
+
end unless definition['packages']['excludes'].nil?
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def merge_post_operations
|
160
|
+
for appliance_name in @current_appliances
|
161
|
+
definition = @appliance_definitions[appliance_name]
|
162
|
+
|
163
|
+
unless definition['post'].nil?
|
164
|
+
for cmd in definition['post']['base']
|
165
|
+
@appliance_config.post.base << cmd
|
166
|
+
end unless definition['post']['base'].nil?
|
167
|
+
|
168
|
+
for cmd in definition['post']['ec2']
|
169
|
+
@appliance_config.post.ec2 << cmd
|
170
|
+
end unless definition['post']['ec2'].nil?
|
171
|
+
|
172
|
+
for cmd in definition['post']['vmware']
|
173
|
+
@appliance_config.post.vmware << cmd
|
174
|
+
end unless definition['post']['vmware'].nil?
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def merge_field( field, section )
|
181
|
+
for appliance_name in @current_appliances
|
182
|
+
appliance_definition = @appliance_definitions[appliance_name]
|
183
|
+
next if appliance_definition[section].nil? or appliance_definition[section][field].nil?
|
184
|
+
val = appliance_definition[section][field]
|
185
|
+
yield val
|
186
|
+
end unless @appliance_config.definition['appliances'].nil?
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_appliances( appliance_name )
|
190
|
+
appliances = []
|
191
|
+
|
192
|
+
if @appliance_definitions.has_key?( appliance_name )
|
193
|
+
definition = @appliance_definitions[appliance_name]
|
194
|
+
# add current appliance name
|
195
|
+
appliances << definition['name']
|
196
|
+
|
197
|
+
definition['appliances'].each do |appl|
|
198
|
+
appliances += get_appliances( appl ) unless appliances.include?( appl )
|
199
|
+
end unless definition['appliances'].nil? or definition['appliances'].empty?
|
200
|
+
else
|
201
|
+
raise ApplianceValidationError, "Not valid appliance name: Specified appliance name '#{appliance_name}' could not be found in appliance list. Please correct your definition file."
|
202
|
+
end
|
203
|
+
|
204
|
+
appliances
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
require 'logger'
|
22
|
+
|
23
|
+
module BoxGrinder
|
24
|
+
class ExecHelper
|
25
|
+
def initialize( options = {} )
|
26
|
+
@log = options[:log] || Logger.new(STDOUT)
|
27
|
+
end
|
28
|
+
|
29
|
+
def execute( command )
|
30
|
+
@log.debug "Executing command: '#{command}'"
|
31
|
+
|
32
|
+
out = `#{command} 2>&1`
|
33
|
+
|
34
|
+
formatted_output = "Command return:\r\n+++++\r\n#{out}+++++"
|
35
|
+
|
36
|
+
if $?.to_i != 0
|
37
|
+
@log.error formatted_output
|
38
|
+
raise "An error occurred executing command: '#{command}'"
|
39
|
+
else
|
40
|
+
@log.debug formatted_output unless out.strip.length == 0
|
41
|
+
@log.debug "Command '#{command}' executed successfully"
|
42
|
+
return out
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
require 'logger'
|
22
|
+
require 'boxgrinder-core/defaults'
|
23
|
+
|
24
|
+
module BoxGrinder
|
25
|
+
class LogHelper
|
26
|
+
|
27
|
+
THRESHOLDS = {
|
28
|
+
:fatal => Logger::FATAL,
|
29
|
+
:debug => Logger::DEBUG,
|
30
|
+
:error => Logger::ERROR,
|
31
|
+
:warn => Logger::WARN,
|
32
|
+
:info => Logger::INFO
|
33
|
+
}
|
34
|
+
|
35
|
+
def initialize( log_location = ENV['BG_LOG_LOCATION'] )
|
36
|
+
threshold = ENV['BG_LOG_THRESHOLD']
|
37
|
+
log_location ||= DEFAULT_LOCATION[:log]
|
38
|
+
|
39
|
+
unless File.directory?(File.dirname(log_location))
|
40
|
+
FileUtils.mkdir_p(File.dirname(log_location))
|
41
|
+
end
|
42
|
+
|
43
|
+
threshold = THRESHOLDS[threshold.to_sym] unless threshold.nil?
|
44
|
+
|
45
|
+
@stdout_log = Logger.new(STDOUT)
|
46
|
+
@stdout_log.level = threshold || Logger::INFO
|
47
|
+
|
48
|
+
@file_log = Logger.new( log_location, 10, 1024000 )
|
49
|
+
@file_log.level = Logger::DEBUG
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing( method_name, *args )
|
53
|
+
if THRESHOLDS.keys.include?( method_name )
|
54
|
+
@stdout_log.send( method_name, *args )
|
55
|
+
@file_log.send( method_name, *args )
|
56
|
+
else
|
57
|
+
raise NoMethodError
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
require 'boxgrinder-core/defaults'
|
22
|
+
require 'ostruct'
|
23
|
+
require 'rbconfig'
|
24
|
+
|
25
|
+
module BoxGrinder
|
26
|
+
class ApplianceConfig
|
27
|
+
def initialize( definition )
|
28
|
+
@definition = definition
|
29
|
+
|
30
|
+
@name = @definition['name']
|
31
|
+
@summary = @definition['summary']
|
32
|
+
|
33
|
+
@os = OpenStruct.new
|
34
|
+
|
35
|
+
@os.name = APPLIANCE_DEFAULTS[:os][:name]
|
36
|
+
@os.version = APPLIANCE_DEFAULTS[:os][:version]
|
37
|
+
@os.password = APPLIANCE_DEFAULTS[:os][:password]
|
38
|
+
|
39
|
+
@hardware = OpenStruct.new
|
40
|
+
|
41
|
+
@hardware.cpus = 0
|
42
|
+
@hardware.memory = 0
|
43
|
+
@hardware.network = APPLIANCE_DEFAULTS[:hardware][:network]
|
44
|
+
|
45
|
+
@post = OpenStruct.new
|
46
|
+
|
47
|
+
@post.base = []
|
48
|
+
@post.ec2 = []
|
49
|
+
@post.vmware = []
|
50
|
+
|
51
|
+
@appliances = []
|
52
|
+
@repos = []
|
53
|
+
@packages = []
|
54
|
+
@version = 1
|
55
|
+
@release = 0
|
56
|
+
end
|
57
|
+
|
58
|
+
attr_reader :definition
|
59
|
+
attr_reader :name
|
60
|
+
attr_reader :summary
|
61
|
+
attr_reader :appliances
|
62
|
+
attr_reader :os
|
63
|
+
attr_reader :hardware
|
64
|
+
attr_reader :repos
|
65
|
+
attr_reader :packages
|
66
|
+
attr_reader :path
|
67
|
+
attr_reader :file
|
68
|
+
|
69
|
+
attr_accessor :version
|
70
|
+
attr_accessor :release
|
71
|
+
attr_accessor :post
|
72
|
+
|
73
|
+
def init
|
74
|
+
init_arch
|
75
|
+
initialize_paths
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def init_arch
|
80
|
+
@hardware.arch = RbConfig::CONFIG['host_cpu']
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize_paths
|
85
|
+
@path = OpenStruct.new
|
86
|
+
|
87
|
+
@path.dir = OpenStruct.new
|
88
|
+
@path.dir.raw = OpenStruct.new
|
89
|
+
@path.dir.ec2 = OpenStruct.new
|
90
|
+
@path.dir.vmware = OpenStruct.new
|
91
|
+
|
92
|
+
@path.file = OpenStruct.new
|
93
|
+
@path.file.raw = OpenStruct.new
|
94
|
+
@path.file.ec2 = OpenStruct.new
|
95
|
+
@path.file.vmware = OpenStruct.new
|
96
|
+
@path.file.vmware.personal = OpenStruct.new
|
97
|
+
@path.file.vmware.enterprise = OpenStruct.new
|
98
|
+
|
99
|
+
@path.dir.packages = "build/#{appliance_path}/packages"
|
100
|
+
|
101
|
+
@path.dir.raw.build = "build/#{appliance_path}/raw"
|
102
|
+
@path.dir.raw.build_full = "build/#{appliance_path}/raw/#{@name}"
|
103
|
+
|
104
|
+
@path.dir.ec2.build = "build/#{appliance_path}/ec2"
|
105
|
+
@path.dir.ec2.bundle = "#{@path.dir.ec2.build}/bundle"
|
106
|
+
|
107
|
+
@path.dir.vmware.build = "build/#{appliance_path}/vmware"
|
108
|
+
@path.dir.vmware.personal = "#{@path.dir.vmware.build}/personal"
|
109
|
+
@path.dir.vmware.enterprise = "#{@path.dir.vmware.build}/enterprise"
|
110
|
+
|
111
|
+
@path.file.raw.kickstart = "#{@path.dir.raw.build}/#{@name}.ks"
|
112
|
+
@path.file.raw.config = "#{@path.dir.raw.build}/#{@name}.cfg"
|
113
|
+
@path.file.raw.yum = "#{@path.dir.raw.build}/#{@name}.yum.conf"
|
114
|
+
@path.file.raw.disk = "#{@path.dir.raw.build_full}/#{@name}-sda.raw"
|
115
|
+
@path.file.raw.xml = "#{@path.dir.raw.build_full}/#{@name}.xml"
|
116
|
+
|
117
|
+
@path.file.ec2.disk = "#{@path.dir.ec2.build}/#{@name}.ec2"
|
118
|
+
@path.file.ec2.manifest = "#{@path.dir.ec2.bundle}/#{@name}.ec2.manifest.xml"
|
119
|
+
|
120
|
+
@path.file.vmware.disk = "#{@path.dir.vmware.build}/#{@name}-sda.raw"
|
121
|
+
@path.file.vmware.personal.vmx = "#{@path.dir.vmware.personal}/#{@name}.vmx"
|
122
|
+
@path.file.vmware.personal.vmdk = "#{@path.dir.vmware.personal}/#{@name}.vmdk"
|
123
|
+
@path.file.vmware.personal.disk = "#{@path.dir.vmware.personal}/#{@name}-sda.raw"
|
124
|
+
@path.file.vmware.enterprise.vmx = "#{@path.dir.vmware.enterprise}/#{@name}.vmx"
|
125
|
+
@path.file.vmware.enterprise.vmdk = "#{@path.dir.vmware.enterprise}/#{@name}.vmdk"
|
126
|
+
@path.file.vmware.enterprise.disk = "#{@path.dir.vmware.enterprise}/#{@name}-sda.raw"
|
127
|
+
|
128
|
+
@path.file.package = {
|
129
|
+
:raw => {
|
130
|
+
:tgz => "#{@path.dir.packages}/#{@name}-#{@version}.#{@release}-#{@hardware.arch}-raw.tgz",
|
131
|
+
:zip => "#{@path.dir.packages}/#{@name}-#{@version}.#{@release}-#{@hardware.arch}-raw.zip"
|
132
|
+
},
|
133
|
+
:vmware => {
|
134
|
+
:tgz => "#{@path.dir.packages}/#{@name}-#{@version}.#{@release}-#{@hardware.arch}-VMware.tgz",
|
135
|
+
:zip => "#{@path.dir.packages}/#{@name}-#{@version}.#{@release}-#{@hardware.arch}-VMware.zip"
|
136
|
+
}
|
137
|
+
}
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
# used to checking if configuration differs from previous in appliance-kickstart
|
142
|
+
def hash
|
143
|
+
"#{@name}-#{@summary}-#{@version}-#{@release}-#{@os.name}-#{@os.version}-#{@os.password}-#{@hardware.cpus}-#{@hardware.memory}-#{@hardware.partitions}-#{@appliances.join("-")}".hash
|
144
|
+
end
|
145
|
+
|
146
|
+
def simple_name
|
147
|
+
@name
|
148
|
+
end
|
149
|
+
|
150
|
+
def os_path
|
151
|
+
"#{@os.name}/#{@os.version}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def main_path
|
155
|
+
"#{@hardware.arch}/#{os_path}"
|
156
|
+
end
|
157
|
+
|
158
|
+
def appliance_path
|
159
|
+
"appliances/#{main_path}/#{@name}"
|
160
|
+
end
|
161
|
+
|
162
|
+
def eql?(other)
|
163
|
+
hash.eql?(other.hash)
|
164
|
+
end
|
165
|
+
|
166
|
+
def is64bit?
|
167
|
+
@hardware.arch.eql?("x86_64")
|
168
|
+
end
|
169
|
+
|
170
|
+
def is_os_version_stable?
|
171
|
+
DEVELOPMENT_RELEASES[@os.name].eql?(@os.version)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
require 'boxgrinder-core/defaults'
|
22
|
+
require 'ostruct'
|
23
|
+
require 'rbconfig'
|
24
|
+
|
25
|
+
module BoxGrinder
|
26
|
+
class Config
|
27
|
+
def initialize( name, version, release, dir, config_file )
|
28
|
+
@name = name
|
29
|
+
@dir = dir
|
30
|
+
@config_file = config_file
|
31
|
+
|
32
|
+
@version = OpenStruct.new
|
33
|
+
@version.version = version
|
34
|
+
@version.release = release
|
35
|
+
|
36
|
+
@files = OpenStruct.new
|
37
|
+
@data = {}
|
38
|
+
|
39
|
+
if File.exists?( @config_file )
|
40
|
+
@data = YAML.load_file( @config_file )
|
41
|
+
@data['gpg_password'].gsub!(/\$/, "\\$") unless @data['gpg_password'].nil? or @data['gpg_password'].length == 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :name
|
46
|
+
attr_reader :version
|
47
|
+
attr_reader :release
|
48
|
+
attr_reader :data
|
49
|
+
attr_reader :config_file
|
50
|
+
attr_reader :dir
|
51
|
+
attr_reader :files
|
52
|
+
|
53
|
+
def version_with_release
|
54
|
+
@version.version + ((@version.release.nil? or @version.release.empty?) ? "" : "-" + @version.release)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
module BoxGrinder
|
22
|
+
class Task
|
23
|
+
def initialize( action, description, data = {} )
|
24
|
+
@created_at = Time.now
|
25
|
+
@action = action
|
26
|
+
@description = description
|
27
|
+
@data = data
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :action
|
31
|
+
attr_reader :description
|
32
|
+
attr_reader :created_at
|
33
|
+
attr_reader :data
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
require 'boxgrinder-core/validators/errors'
|
22
|
+
require 'boxgrinder-core/defaults'
|
23
|
+
|
24
|
+
module BoxGrinder
|
25
|
+
class ApplianceDefinitionValidator
|
26
|
+
def initialize( appliance_definition )
|
27
|
+
@appliance_definition = appliance_definition
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate
|
31
|
+
check_for_missing_field( 'name' )
|
32
|
+
|
33
|
+
validate_os
|
34
|
+
validate_hardware
|
35
|
+
validate_repos
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def check_for_missing_field( name )
|
41
|
+
raise ApplianceValidationError, "Missing field: appliance definition file should have field '#{name}'" if @appliance_definition[name].nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_os
|
45
|
+
return if @appliance_definition['os'].nil?
|
46
|
+
|
47
|
+
raise ApplianceValidationError, "Unsupported OS: operating system '#{@appliance_definition['os']['name']}' is not supported. Supported OS types: #{SUPPORTED_OSES.keys.join(", ")}. Please correct your appliance definition file, thanks." if !@appliance_definition['os']['name'].nil? and !SUPPORTED_OSES.keys.include?( @appliance_definition['os']['name'] )
|
48
|
+
|
49
|
+
#unless @appliance_definition['os']['version'].nil?
|
50
|
+
#@appliance_definition['os']['version'] = @appliance_definition['os']['version'].to_s
|
51
|
+
#raise ApplianceValidationError, "Not valid OS version: operating system version '#{@appliance_definition['os']['version']}' is not supported for OS type '#{@appliance_definition['os']['name']}'. Supported OS versions for this OS type are: #{SUPPORTED_OSES[@appliance_definition['os']['name']].join(", ")}. Please correct your definition file '#{@appliance_definition_file}', thanks" if !SUPPORTED_OSES[@appliance_definition['os']['name'].nil? ? APPLIANCE_DEFAULTS[:os][:name] : @appliance_definition['os']['name']].include?( @appliance_definition['os']['version'] )
|
52
|
+
#end
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_hardware
|
56
|
+
return if @appliance_definition['hardware'].nil?
|
57
|
+
|
58
|
+
unless @appliance_definition['hardware']['cpus'].nil?
|
59
|
+
raise ApplianceValidationError, "Not valid CPU amount: '#{@appliance_definition['hardware']['cpus']}' is not allowed here. Please correct your appliance definition file, thanks." if @appliance_definition['hardware']['cpus'] =~ /\d/
|
60
|
+
raise ApplianceValidationError, "Not valid CPU amount: Too many or too less CPU's: '#{@appliance_definition['hardware']['cpus']}'. Please choose from 1-4. Please correct your appliance definition file, thanks." unless @appliance_definition['hardware']['cpus'] >= 1 and @appliance_definition['hardware']['cpus'] <= 4
|
61
|
+
end
|
62
|
+
|
63
|
+
unless @appliance_definition['hardware']['memory'].nil?
|
64
|
+
raise ApplianceValidationError, "Not valid memory amount: '#{@appliance_definition['hardware']['memory']}' is wrong value. Please correct your appliance definition file, thanks." if @appliance_definition['hardware']['memory'] =~ /\d/
|
65
|
+
raise ApplianceValidationError, "Not valid memory amount: '#{@appliance_definition['hardware']['memory']}' is not allowed here. Memory should be a multiplicity of 64. Please correct your appliance definition file, thanks." if (@appliance_definition['hardware']['memory'].to_i % 64 > 0)
|
66
|
+
end
|
67
|
+
|
68
|
+
unless @appliance_definition['hardware']['partitions'].nil?
|
69
|
+
raise ApplianceValidationError, "Not valid partitions format: Please correct your appliance definition file, thanks." unless @appliance_definition['hardware']['partitions'].class.eql?(Array)
|
70
|
+
|
71
|
+
for partition in @appliance_definition['hardware']['partitions']
|
72
|
+
raise ApplianceValidationError, "Not valid partition format: '#{partition}' is wrong value. Please correct your appliance definition file, thanks." unless partition.class.eql?(Hash)
|
73
|
+
raise ApplianceValidationError, "Not valid partition format: Keys 'root' and 'size' should be specified for every partition. Please correct your appliance definition file, thanks." if !partition.keys.include?("root") or !partition.keys.include?("size")
|
74
|
+
raise ApplianceValidationError, "Not valid partition size: '#{partition['size']}' is not a valid value. Please correct your appliance definition file, thanks." if partition['size'] =~ /\d/ or partition['size'].to_i < 1
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def validate_repos
|
80
|
+
return if @appliance_definition['repos'].nil?
|
81
|
+
raise ApplianceValidationError, "Not valid repos format: Please correct your appliance definition file, thanks." unless @appliance_definition['repos'].class.eql?(Array)
|
82
|
+
|
83
|
+
for repo in @appliance_definition['repos']
|
84
|
+
raise ApplianceValidationError, "Not valid repo format: '#{repo}' is wrong value. Please correct your appliance definition file, thanks." unless repo.class.eql?(Hash)
|
85
|
+
raise ApplianceValidationError, "Not valid repo format: Please specify name for repository. Please correct your appliance definition file, thanks." unless repo.keys.include?('name')
|
86
|
+
raise ApplianceValidationError, "Not valid repo format: There is no 'mirrorlist' or 'baseurl' specified for '#{repo['name']}' repository. Please correct your appliance definition file, thanks." unless repo.keys.include?('mirrorlist') or repo.keys.include?('baseurl')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# JBoss, Home of Professional Open Source
|
2
|
+
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
+
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
+
# full listing of individual contributors.
|
5
|
+
#
|
6
|
+
# This is free software; you can redistribute it and/or modify it
|
7
|
+
# under the terms of the GNU Lesser General Public License as
|
8
|
+
# published by the Free Software Foundation; either version 2.1 of
|
9
|
+
# the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This software is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this software; if not, write to the Free
|
18
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
+
|
21
|
+
module BoxGrinder
|
22
|
+
class ValidationError < StandardError
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class ApplianceValidationError < ValidationError
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class StandardError
|
32
|
+
def info
|
33
|
+
"#{self.class}: #{message}#$/#{backtrace.join($/)}"
|
34
|
+
end
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: boxgrinder-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- BoxGrinder Project
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-15 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: info@boxgrinder.org
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/boxgrinder-core.rb
|
31
|
+
- lib/boxgrinder-core/models/appliance-config.rb
|
32
|
+
- lib/boxgrinder-core/models/config.rb
|
33
|
+
- lib/boxgrinder-core/models/task.rb
|
34
|
+
- lib/boxgrinder-core/defaults.rb
|
35
|
+
- lib/boxgrinder-core/validators/errors.rb
|
36
|
+
- lib/boxgrinder-core/validators/appliance-definition-validator.rb
|
37
|
+
- lib/boxgrinder-core/helpers/exec-helper.rb
|
38
|
+
- lib/boxgrinder-core/helpers/log-helper.rb
|
39
|
+
- lib/boxgrinder-core/helpers/appliance-config-helper.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://www.jboss.org/stormgrind/projects/boxgrinder.html
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.6
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: BoxGrinder Core files
|
70
|
+
test_files: []
|
71
|
+
|