rconf 0.5.0

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.
@@ -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