rconf 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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