rconf 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +56 -0
- data/Rakefile +63 -0
- data/bin/rconf +102 -0
- data/examples/sample.rc +9 -0
- data/lib/rconf.rb +24 -0
- data/lib/rconf/command.rb +112 -0
- data/lib/rconf/configurator.rb +179 -0
- data/lib/rconf/configurator_registry.rb +63 -0
- data/lib/rconf/configurators/bundler_configurator.rb +85 -0
- data/lib/rconf/configurators/ruby_configurator.rb +151 -0
- data/lib/rconf/language.rb +91 -0
- data/lib/rconf/platform.rb +114 -0
- data/lib/rconf/platforms/darwin.rb +27 -0
- data/lib/rconf/platforms/linux.rb +40 -0
- data/lib/rconf/platforms/windows.rb +40 -0
- data/lib/rconf/progress_reporter.rb +72 -0
- data/lib/rconf/progress_reporters/base_reporter.rb +156 -0
- data/lib/rconf/progress_reporters/file_reporter.rb +58 -0
- data/lib/rconf/progress_reporters/stdout_reporter.rb +83 -0
- data/lib/rconf/ruby_extensions.rb +56 -0
- data/lib/rconf/trollop.rb +782 -0
- data/lib/rconf/version.rb +30 -0
- data/rconf.gemspec +24 -0
- data/spec/command_spec.rb +38 -0
- data/spec/configurator_spec.rb +64 -0
- data/spec/configurators/bundler_configurator_spec.rb +51 -0
- data/spec/configurators/ruby_configurator_spec.rb +60 -0
- data/spec/language_spec.rb +60 -0
- data/spec/platform_spec.rb +37 -0
- data/spec/progress_reporters/base_reporter_spec.rb +84 -0
- data/spec/progress_reporters/file_reporter_spec.rb +31 -0
- data/spec/progress_reporters/stdout_reporter_spec.rb +23 -0
- data/spec/ruby_extensions_spec.rb +35 -0
- data/spec/spec_helper.rb +21 -0
- metadata +129 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
# Configurator mixin, defines DSL and common validation method
|
15
|
+
class ConfiguratorRegistry
|
16
|
+
|
17
|
+
include Singleton
|
18
|
+
|
19
|
+
# Associate configurator with given key
|
20
|
+
#
|
21
|
+
# === Parameters
|
22
|
+
# key(Symbol):: Key configurator should be associated with
|
23
|
+
# value(Class):: Associated configurator class
|
24
|
+
#
|
25
|
+
# === Return
|
26
|
+
# value(Class):: Configurator class
|
27
|
+
def []=(key, value)
|
28
|
+
@configurators[key] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
# Configurator class for given key
|
32
|
+
#
|
33
|
+
# === Parameters
|
34
|
+
# key(String):: Configurator for given key
|
35
|
+
#
|
36
|
+
# === Return
|
37
|
+
# cfg_class(Constant):: Configurator class if there is one
|
38
|
+
# nil:: Otherwise
|
39
|
+
def [](key)
|
40
|
+
@configurators[key]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Iterate through all configurators
|
44
|
+
#
|
45
|
+
# === Block
|
46
|
+
# Block should take one argument which is the configurator being iterated on
|
47
|
+
#
|
48
|
+
# === Return
|
49
|
+
# true:: Always return true
|
50
|
+
def each(&blk)
|
51
|
+
@configurators.each(&blk)
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
# Initialize configurators hash
|
58
|
+
def initialize
|
59
|
+
@configurators = Hash.new
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
class BundlerConfigurator
|
15
|
+
|
16
|
+
DEFAULT_GEM_PATH = 'vendor/system_gems/cache'
|
17
|
+
|
18
|
+
include Configurator
|
19
|
+
|
20
|
+
register :bundler
|
21
|
+
|
22
|
+
description 'Installs bundler and runs "bundle install"'
|
23
|
+
|
24
|
+
settings :bundler_version => 'Version of bundler gem, e.g. "1.0.10"',
|
25
|
+
:bundler_gem_path => 'Path to bundler gem, e.g. "vendor/system_gems/cache"'
|
26
|
+
|
27
|
+
validate_has_settings :bundler_version
|
28
|
+
|
29
|
+
# Install bundler if needed and run bundle install
|
30
|
+
#
|
31
|
+
# === Return
|
32
|
+
# true:: Always return true
|
33
|
+
def run_linux
|
34
|
+
report_check("Checking for bundler #{bundler_version}")
|
35
|
+
res = Command.execute('bundle', '--version')
|
36
|
+
success = (res.output =~ /#{bundler_version}/)
|
37
|
+
report_result(success)
|
38
|
+
install_bundler(res.success?) unless success
|
39
|
+
report_check('Installing gems')
|
40
|
+
res = Command.execute('bundle', 'install', :abort_on_failure => 'Failed to install gems')
|
41
|
+
report_success
|
42
|
+
true
|
43
|
+
end
|
44
|
+
alias :run_darwin :run_linux
|
45
|
+
|
46
|
+
# Not implemented on windows (no bundler gem there)
|
47
|
+
#
|
48
|
+
# === Raise
|
49
|
+
# (Exception):: Always raise
|
50
|
+
def run_windows
|
51
|
+
raise "Bundler is not supported on Windows!"
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
# Install bundler from gem in cache
|
57
|
+
#
|
58
|
+
# === Parameters
|
59
|
+
# exists(FalseClass|TrueClass):: Whether bundler is already installed
|
60
|
+
# (but is the wrong version)
|
61
|
+
#
|
62
|
+
# === Return
|
63
|
+
# true:: Always return true
|
64
|
+
#
|
65
|
+
# === Raise
|
66
|
+
# (Exception):: If bundler gem cannot be found or installed
|
67
|
+
def install_bundler(exists)
|
68
|
+
if exists
|
69
|
+
report_check('Uninstalling existing versions of bundler')
|
70
|
+
res = Command.execute('gem', 'uninstall', 'bundler', '-a', '-x',
|
71
|
+
:abort_on_failure => 'Failed to uninstall bundler')
|
72
|
+
report_success
|
73
|
+
end
|
74
|
+
report_check("Installing bundler #{bundler_version}")
|
75
|
+
bundler_gem_path DEFAULT_GEM_PATH unless bundler_gem_path
|
76
|
+
bundler_file = File.join(bundler_gem_path, "bundler-#{bundler_version}.gem")
|
77
|
+
report_fatal("Missing bundler gem at #{bundler_file}") unless File.exist?(bundler_file)
|
78
|
+
res = Command.execute('gem','install', bundler_file, '--no-ri', '--no-rdoc',
|
79
|
+
:abort_on_failure => 'Failed to install bundler')
|
80
|
+
report_success
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
class RubyConfigurator
|
15
|
+
|
16
|
+
# RVM version used to install rubies
|
17
|
+
RVM_VERSION = '1.2.6'
|
18
|
+
|
19
|
+
include Configurator
|
20
|
+
|
21
|
+
register :ruby
|
22
|
+
|
23
|
+
description "Installs ruby interpreter and rubygems.\n" +
|
24
|
+
'Installs and uses rvm on supported (i.e. non-Windows) platforms'
|
25
|
+
|
26
|
+
settings :ruby_version => 'Ruby version using rvm notation (see "rvm list known")',
|
27
|
+
:rubygems_version => 'Rubygems version, e.g. "1.3.7"',
|
28
|
+
:gemset => 'Gemset to be used for platforms supporting rvm'
|
29
|
+
|
30
|
+
validate_has_settings :ruby_version, :rubygems_version
|
31
|
+
|
32
|
+
# Switch to ruby version defined in settings
|
33
|
+
# Use rvm and install it if needed
|
34
|
+
#
|
35
|
+
# === Return
|
36
|
+
# true:: Always return true
|
37
|
+
def run_linux
|
38
|
+
check_rvm(RVM_VERSION)
|
39
|
+
report_check("Checking whether #{ruby_version} is the active ruby")
|
40
|
+
out = Command.execute('rvm', 'list').output
|
41
|
+
if out =~ /^=> #{ruby_version.gsub('.', '\\.')}/
|
42
|
+
report_success
|
43
|
+
else
|
44
|
+
report_failure
|
45
|
+
report_check("Switching to #{ruby_version}")
|
46
|
+
out = Command.execute('rvm', 'use', ruby_version).output
|
47
|
+
case out
|
48
|
+
when /is not installed\./
|
49
|
+
report_failure
|
50
|
+
report_fatal "Failed to install #{ruby}: #{@out}" if @out
|
51
|
+
@out = install_ruby(ruby_version)
|
52
|
+
run
|
53
|
+
return true
|
54
|
+
when /^Using /
|
55
|
+
report_success
|
56
|
+
check_rvmrc
|
57
|
+
post_note 'Configuration required switching the active ruby, please "cd" into the project directory again to activate it'
|
58
|
+
else
|
59
|
+
report_fatal("Failed to use #{ruby_version}:\n#{out}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if gemset
|
63
|
+
report_check("Switching to gemset #{gemset}")
|
64
|
+
res = Command.execute('rvm', 'gemset', 'use', gemset,
|
65
|
+
:abort_on_failure => "Failed to switch to gemset '#{gemset}'")
|
66
|
+
report_success
|
67
|
+
end
|
68
|
+
Command.set_prefix("rvm #{ruby_version}@#{gemset} exec --")
|
69
|
+
true
|
70
|
+
end
|
71
|
+
alias :run_darwin :run_linux
|
72
|
+
|
73
|
+
# Switch to ruby version defined in settings
|
74
|
+
# TBD
|
75
|
+
#
|
76
|
+
# === Return
|
77
|
+
# true:: Always return true
|
78
|
+
def run_windows
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Check whether the right version of RVM is installed and install it if not
|
84
|
+
#
|
85
|
+
# === Parameters
|
86
|
+
# version(String):: Version of RVM to be checked, e.g. '1.2.6'
|
87
|
+
#
|
88
|
+
# === Return
|
89
|
+
# true:: Always return true
|
90
|
+
def check_rvm(version)
|
91
|
+
report_check("Checking that rvm #{version} is installed")
|
92
|
+
out = Command.execute('rvm', '--version').output
|
93
|
+
if out =~ /rvm #{RVM_VERSION.gsub('.', '\\.')}/
|
94
|
+
report_success
|
95
|
+
else
|
96
|
+
report_failure
|
97
|
+
report_check("Installing rvm #{version}")
|
98
|
+
rvm_src = File.join(ENV['HOME'] || '/root', '.rvm/src')
|
99
|
+
FileUtils.mkdir_p(rvm_src)
|
100
|
+
Dir.chdir(rvm_src) do
|
101
|
+
res = Command.execute('curl', '-O', '-f',
|
102
|
+
"http://rvm.beginrescueend.com/releases/rvm-#{version}.tar.gz",
|
103
|
+
:abort_on_failure => "Failed to download rvm #{version}")
|
104
|
+
Command.execute('tar', 'zxf', "rvm-#{version}.tar.gz")
|
105
|
+
end
|
106
|
+
Dir.chdir(File.join(rvm_src, "rvm-#{version}")) do
|
107
|
+
res = Command.execute('./install', :abort_on_failure => "Failed to install rvm #{version}")
|
108
|
+
end
|
109
|
+
report_success
|
110
|
+
end
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
# Install given ruby version using rvm
|
115
|
+
#
|
116
|
+
# === Parameters
|
117
|
+
# ruby(String):: Ruby version compatible with rvm
|
118
|
+
#
|
119
|
+
# === Return
|
120
|
+
# out(String):: Installation output
|
121
|
+
def install_ruby(ruby)
|
122
|
+
report_check("Installing #{ruby} (this will take a while, please be patient)")
|
123
|
+
res = Command.execute('rvm', 'install', ruby)
|
124
|
+
report_result(res.success?)
|
125
|
+
res.output
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check .rvmrc and its content
|
129
|
+
#
|
130
|
+
# === Return
|
131
|
+
# true:: Always return true
|
132
|
+
def check_rvmrc
|
133
|
+
report_check('Setting up .rvmrc')
|
134
|
+
begin
|
135
|
+
File.open('.rvmrc', 'w') do |f|
|
136
|
+
f.puts "rvm #{ruby_version}@#{gemset}"
|
137
|
+
f.puts "type -P rconf &>/dev/null && { rconf; }"
|
138
|
+
f.puts "type -P rconf &>/dev/null || { echo 'rconf not installed, skipping (see .rvmrc)'; }"
|
139
|
+
end
|
140
|
+
Command.execute('rvm', 'trust', 'rvmrc')
|
141
|
+
report_success
|
142
|
+
rescue Exception => e
|
143
|
+
report_failure
|
144
|
+
report_error(e.message)
|
145
|
+
end
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
# DSL implementation
|
15
|
+
class Language
|
16
|
+
|
17
|
+
# List of configurators resulting from parsing a configuration
|
18
|
+
attr_reader :configurators
|
19
|
+
|
20
|
+
# Errors generated by configurators validations if any
|
21
|
+
attr_reader :validation_errors
|
22
|
+
|
23
|
+
# Load given file and run content to retrieve configurators
|
24
|
+
#
|
25
|
+
# === Parameters
|
26
|
+
# file(String):: Path to file being loaded
|
27
|
+
#
|
28
|
+
# === Result
|
29
|
+
# lang(Language):: Instance initialized from file
|
30
|
+
def self.load(file)
|
31
|
+
begin
|
32
|
+
content = IO.read(file)
|
33
|
+
rescue Exception => e
|
34
|
+
raise "Failed to load '#{file}': #{e.message}"
|
35
|
+
end
|
36
|
+
parse(content)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Parse given configuration text
|
40
|
+
#
|
41
|
+
# === Parameters
|
42
|
+
# content(String):: Content to be parsed
|
43
|
+
#
|
44
|
+
# === Result
|
45
|
+
# lang(Language):: Instance initialized from content
|
46
|
+
def self.parse(content)
|
47
|
+
lang = new
|
48
|
+
lang.instance_eval(content)
|
49
|
+
lang
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Initialize configurators and validation errors lists
|
55
|
+
# Do not call directly, instead call 'load'
|
56
|
+
def initialize
|
57
|
+
@configurators = Array.new
|
58
|
+
@validation_errors = Array.new
|
59
|
+
end
|
60
|
+
|
61
|
+
# Each missing method should correspond to a configurator section.
|
62
|
+
# Such sections consist of a block which gets eval'ed in the contect of the
|
63
|
+
# corresponding configurator instance.
|
64
|
+
#
|
65
|
+
# === Parameters
|
66
|
+
# meth(Symbol):: Method symbol, should be a configurator
|
67
|
+
# args(Array):: List of arguments
|
68
|
+
# blk(Proc):: Block to be evaled in configurator context
|
69
|
+
#
|
70
|
+
# === Return
|
71
|
+
# true:: Always return true
|
72
|
+
def method_missing(meth, *args, &blk)
|
73
|
+
if blk
|
74
|
+
klass = ConfiguratorRegistry[meth]
|
75
|
+
if klass
|
76
|
+
configurator = klass.new(*args)
|
77
|
+
configurator.instance_eval(&blk)
|
78
|
+
error = configurator.validate
|
79
|
+
@validation_errors << error if error
|
80
|
+
@configurators << configurator
|
81
|
+
else
|
82
|
+
@validation_errors << "Unknown configurator '#{meth}'"
|
83
|
+
end
|
84
|
+
else
|
85
|
+
@validation_errors << "Invalid syntax, expecting block after '#{meth}'"
|
86
|
+
end
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
require 'rbconfig'
|
13
|
+
|
14
|
+
module RightConf
|
15
|
+
|
16
|
+
class Platform
|
17
|
+
|
18
|
+
include Singleton
|
19
|
+
|
20
|
+
|
21
|
+
# Generic platform family
|
22
|
+
#
|
23
|
+
# === Return
|
24
|
+
# family(Symbol):: One of :linux, :windows or :darwin
|
25
|
+
def family
|
26
|
+
@family ||= case RbConfig::CONFIG['host_os']
|
27
|
+
when /mswin|win32|dos|mingw|cygwin/i then :windows
|
28
|
+
when /darwin/i then :darwin
|
29
|
+
when /linux/i then :linux
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is current platform linux?
|
34
|
+
#
|
35
|
+
# === Return
|
36
|
+
# true:: If current platform is linux
|
37
|
+
# false:: Otherwise
|
38
|
+
def linux?
|
39
|
+
return family == :linux
|
40
|
+
end
|
41
|
+
|
42
|
+
# Is current platform darwin?
|
43
|
+
#
|
44
|
+
# === Return
|
45
|
+
# true:: If current platform is darwin
|
46
|
+
# false:: Otherwise
|
47
|
+
def darwin?
|
48
|
+
return family == :darwin
|
49
|
+
end
|
50
|
+
# Is current platform windows?
|
51
|
+
#
|
52
|
+
# === Return
|
53
|
+
# true:: If current platform is Windows
|
54
|
+
# false:: Otherwise
|
55
|
+
def windows?
|
56
|
+
return family == :windows
|
57
|
+
end
|
58
|
+
|
59
|
+
# Call platform specific implementation of method whose symbol is returned
|
60
|
+
# by the passed in block. Arguments are passed through.
|
61
|
+
# e.g.
|
62
|
+
#
|
63
|
+
# Platform.dispatch(2) { :echo }
|
64
|
+
#
|
65
|
+
# will result in 'echo_linux(2)' being executed in self if running on linux,
|
66
|
+
# 'echo_windows(2)' if running on Windows and 'echo_darwin(2)' if on
|
67
|
+
# Mac OS X. Note that the method is run in the instance of the caller.
|
68
|
+
#
|
69
|
+
# === Parameters
|
70
|
+
# args:: Pass-through arguments
|
71
|
+
#
|
72
|
+
# === Block
|
73
|
+
# Given block should not take any argument and return a symbol for the
|
74
|
+
# method that should be called
|
75
|
+
#
|
76
|
+
# === Return
|
77
|
+
# res(ObjecT):: Result returned by platform specific implementation
|
78
|
+
def dispatch(*args, &blk)
|
79
|
+
raise "Platform.dispatch requires a block" unless blk
|
80
|
+
binding = blk.binding.eval('self')
|
81
|
+
meth = blk.call
|
82
|
+
target = dispatch_candidates(meth).detect do |candidate|
|
83
|
+
binding.respond_to?(candidate)
|
84
|
+
end
|
85
|
+
raise "No platform dispatch target found in #{binding.class} for " +
|
86
|
+
"'#{meth.inspect}', tried " + dispatch_candidates(meth).join(', ') unless target
|
87
|
+
binding.__send__(target, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
# Load platform specific implementation
|
93
|
+
def initialize
|
94
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'platforms', family.to_s))
|
95
|
+
init
|
96
|
+
end
|
97
|
+
|
98
|
+
# Candidate platform specific methods for given prefix
|
99
|
+
# Ordered by most platform specific to most generic
|
100
|
+
#
|
101
|
+
# === Parameters
|
102
|
+
# prefix(String):: Method prefix
|
103
|
+
#
|
104
|
+
# === Return
|
105
|
+
# candidates(Array):: List of potential candidates
|
106
|
+
def dispatch_candidates(prefix)
|
107
|
+
candidates = ["#{prefix}_#{family}_#{flavor}_#{release}",
|
108
|
+
"#{prefix}_#{family}_#{flavor}",
|
109
|
+
"#{prefix}_#{family}"]
|
110
|
+
candidates.map(&:to_sym)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|