dhill-sprinkle 0.3.3.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.
Files changed (118) hide show
  1. data/.gitignore +3 -0
  2. data/CREDITS +33 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +242 -0
  6. data/Rakefile +2 -0
  7. data/VERSION +1 -0
  8. data/bin/sprinkle +95 -0
  9. data/examples/packages/build_essential.rb +9 -0
  10. data/examples/packages/databases/mysql.rb +13 -0
  11. data/examples/packages/databases/sqlite3.rb +16 -0
  12. data/examples/packages/phusion.rb +55 -0
  13. data/examples/packages/ruby/rails.rb +9 -0
  14. data/examples/packages/ruby/ruby.rb +17 -0
  15. data/examples/packages/ruby/rubygems.rb +17 -0
  16. data/examples/packages/scm/git.rb +11 -0
  17. data/examples/packages/scm/subversion.rb +4 -0
  18. data/examples/packages/servers/apache.rb +15 -0
  19. data/examples/rails/README +15 -0
  20. data/examples/rails/deploy.rb +2 -0
  21. data/examples/rails/packages/database.rb +9 -0
  22. data/examples/rails/packages/essential.rb +9 -0
  23. data/examples/rails/packages/rails.rb +29 -0
  24. data/examples/rails/packages/scm.rb +11 -0
  25. data/examples/rails/packages/search.rb +11 -0
  26. data/examples/rails/packages/server.rb +28 -0
  27. data/examples/rails/rails.rb +73 -0
  28. data/examples/sprinkle/sprinkle.rb +38 -0
  29. data/lib/sprinkle.rb +3 -0
  30. data/lib/sprinkle/actors/actors.rb +17 -0
  31. data/lib/sprinkle/actors/capistrano.rb +146 -0
  32. data/lib/sprinkle/actors/local.rb +37 -0
  33. data/lib/sprinkle/actors/ssh.rb +177 -0
  34. data/lib/sprinkle/actors/vlad.rb +83 -0
  35. data/lib/sprinkle/configurable.rb +31 -0
  36. data/lib/sprinkle/deployment.rb +73 -0
  37. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  38. data/lib/sprinkle/extensions/array.rb +5 -0
  39. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  40. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  41. data/lib/sprinkle/extensions/string.rb +10 -0
  42. data/lib/sprinkle/extensions/symbol.rb +7 -0
  43. data/lib/sprinkle/installers/apt.rb +52 -0
  44. data/lib/sprinkle/installers/binary.rb +46 -0
  45. data/lib/sprinkle/installers/bsd_port.rb +33 -0
  46. data/lib/sprinkle/installers/deb.rb +41 -0
  47. data/lib/sprinkle/installers/freebsd_pkg.rb +37 -0
  48. data/lib/sprinkle/installers/freebsd_portinstall.rb +36 -0
  49. data/lib/sprinkle/installers/gem.rb +64 -0
  50. data/lib/sprinkle/installers/install_package.rb +79 -0
  51. data/lib/sprinkle/installers/installer.rb +123 -0
  52. data/lib/sprinkle/installers/mac_port.rb +38 -0
  53. data/lib/sprinkle/installers/noop.rb +20 -0
  54. data/lib/sprinkle/installers/openbsd_pkg.rb +47 -0
  55. data/lib/sprinkle/installers/opensolaris_pkg.rb +43 -0
  56. data/lib/sprinkle/installers/push_text.rb +45 -0
  57. data/lib/sprinkle/installers/rake.rb +37 -0
  58. data/lib/sprinkle/installers/replace_text.rb +45 -0
  59. data/lib/sprinkle/installers/rpm.rb +37 -0
  60. data/lib/sprinkle/installers/runner.rb +18 -0
  61. data/lib/sprinkle/installers/smart.rb +29 -0
  62. data/lib/sprinkle/installers/source.rb +201 -0
  63. data/lib/sprinkle/installers/transfer.rb +178 -0
  64. data/lib/sprinkle/installers/user.rb +15 -0
  65. data/lib/sprinkle/installers/yum.rb +37 -0
  66. data/lib/sprinkle/installers/zypper.rb +43 -0
  67. data/lib/sprinkle/package.rb +326 -0
  68. data/lib/sprinkle/policy.rb +125 -0
  69. data/lib/sprinkle/script.rb +23 -0
  70. data/lib/sprinkle/verifiers/apt.rb +21 -0
  71. data/lib/sprinkle/verifiers/directory.rb +16 -0
  72. data/lib/sprinkle/verifiers/executable.rb +53 -0
  73. data/lib/sprinkle/verifiers/file.rb +34 -0
  74. data/lib/sprinkle/verifiers/package.rb +26 -0
  75. data/lib/sprinkle/verifiers/process.rb +21 -0
  76. data/lib/sprinkle/verifiers/rpm.rb +21 -0
  77. data/lib/sprinkle/verifiers/ruby.rb +25 -0
  78. data/lib/sprinkle/verifiers/symlink.rb +30 -0
  79. data/lib/sprinkle/verify.rb +114 -0
  80. data/lib/sprinkle/version.rb +3 -0
  81. data/script/console +8 -0
  82. data/script/destroy +14 -0
  83. data/script/generate +14 -0
  84. data/spec/spec.opts +1 -0
  85. data/spec/spec_helper.rb +17 -0
  86. data/spec/sprinkle/actors/capistrano_spec.rb +265 -0
  87. data/spec/sprinkle/actors/local_spec.rb +29 -0
  88. data/spec/sprinkle/configurable_spec.rb +46 -0
  89. data/spec/sprinkle/deployment_spec.rb +80 -0
  90. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  91. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  92. data/spec/sprinkle/installers/apt_spec.rb +70 -0
  93. data/spec/sprinkle/installers/bsd_port_spec.rb +42 -0
  94. data/spec/sprinkle/installers/freebsd_pkg_spec.rb +49 -0
  95. data/spec/sprinkle/installers/freebsd_portinstall_spec.rb +42 -0
  96. data/spec/sprinkle/installers/gem_spec.rb +107 -0
  97. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  98. data/spec/sprinkle/installers/mac_port_spec.rb +42 -0
  99. data/spec/sprinkle/installers/noop_spec.rb +23 -0
  100. data/spec/sprinkle/installers/openbsd_pkg_spec.rb +49 -0
  101. data/spec/sprinkle/installers/opensolaris_pkg_spec.rb +49 -0
  102. data/spec/sprinkle/installers/push_text_spec.rb +66 -0
  103. data/spec/sprinkle/installers/rake_spec.rb +29 -0
  104. data/spec/sprinkle/installers/replace_text_spec.rb +45 -0
  105. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  106. data/spec/sprinkle/installers/runner_spec.rb +31 -0
  107. data/spec/sprinkle/installers/source_spec.rb +371 -0
  108. data/spec/sprinkle/installers/transfer_spec.rb +98 -0
  109. data/spec/sprinkle/installers/yum_spec.rb +49 -0
  110. data/spec/sprinkle/installers/zypper_spec.rb +49 -0
  111. data/spec/sprinkle/package_spec.rb +474 -0
  112. data/spec/sprinkle/policy_spec.rb +126 -0
  113. data/spec/sprinkle/script_spec.rb +51 -0
  114. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  115. data/spec/sprinkle/verify_spec.rb +173 -0
  116. data/sprinkle-0.3.3.1.gem +0 -0
  117. data/sprinkle.gemspec +26 -0
  118. metadata +281 -0
@@ -0,0 +1,178 @@
1
+ # Blatantly stole this from Chef
2
+ class TemplateError < RuntimeError
3
+ attr_reader :original_exception, :context
4
+ SOURCE_CONTEXT_WINDOW = 2 unless defined? SOURCE_CONTEXT_WINDOW
5
+
6
+ def initialize(original_exception, template, context)
7
+ @original_exception, @template, @context = original_exception, template, context
8
+ end
9
+
10
+ def message
11
+ @original_exception.message
12
+ end
13
+
14
+ def line_number
15
+ @line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ }
16
+ end
17
+
18
+ def source_location
19
+ "on line ##{line_number}"
20
+ end
21
+
22
+ def source_listing
23
+ return nil if line_number.nil?
24
+
25
+ @source_listing ||= begin
26
+ line_index = line_number - 1
27
+ beginning_line = line_index <= SOURCE_CONTEXT_WINDOW ? 0 : line_index - SOURCE_CONTEXT_WINDOW
28
+ source_size = SOURCE_CONTEXT_WINDOW * 2 + 1
29
+ lines = @template.split(/\n/)
30
+ contextual_lines = lines[beginning_line, source_size]
31
+ output = []
32
+ contextual_lines.each_with_index do |line, index|
33
+ line_number = (index+beginning_line+1).to_s.rjust(3)
34
+ output << "#{line_number}: #{line}"
35
+ end
36
+ output.join("\n")
37
+ end
38
+ end
39
+
40
+ def to_s
41
+ "\n\n#{self.class} (#{message}) #{source_location}:\n\n" +
42
+ "#{source_listing}\n\n #{original_exception.backtrace.join("\n ")}\n\n"
43
+ end
44
+ end
45
+
46
+ module Sprinkle
47
+ module Installers
48
+ # Beware, another strange "installer" coming your way.
49
+ #
50
+ # = File transfer installer
51
+ #
52
+ # This installer pushes files from the local disk to remote servers.
53
+ #
54
+ # == Example Usage
55
+ #
56
+ # Installing a nginx.conf onto remote servers
57
+ #
58
+ # package :nginx_conf do
59
+ # transfer 'files/nginx.conf', '/etc/nginx.conf'
60
+ # end
61
+ #
62
+ # If you user has access to 'sudo' and theres a file that requires
63
+ # priveledges, you can pass :sudo => true
64
+ #
65
+ # package :nginx_conf do
66
+ # transfer 'files/nginx.conf', '/etc/nginx.conf', :sudo => true
67
+ # end
68
+ #
69
+ # By default, transfers are recursive and you can move whole directories
70
+ # via this method. If you wish to disable recursive transfers, you can pass
71
+ # recursive => false, although it will not be obeyed when using the Vlad actor.
72
+ #
73
+ # If you pass the option :render => true, this tells transfer that the source file
74
+ # is an ERB template to be rendered locally before being transferred (you can declare
75
+ # variables in the package scope). When render is true, recursive is turned off. Note
76
+ # you can also explicitly pass locals in to render with the :locals option.
77
+ #
78
+ # package :nginx_conf do
79
+ # nginx_port = 8080
80
+ # transfer 'files/nginx.conf', '/etc/nginx.conf', :render => true
81
+ # end
82
+ #
83
+ # Finally, should you need to run commands before or after the file transfer (making
84
+ # directories or changing permissions), you can use the pre/post :install directives
85
+ # and they will be run.
86
+ class Transfer < Installer
87
+ attr_accessor :source, :destination #:nodoc:
88
+
89
+ def initialize(parent, source, destination, options={}, &block) #:nodoc:
90
+ super parent, options, &block
91
+ @source = source
92
+ @destination = destination
93
+ end
94
+
95
+ def install_commands
96
+ nil
97
+ end
98
+
99
+ def self.render_template(template, context, prefix)
100
+ require 'tempfile'
101
+ require 'erubis'
102
+
103
+ begin
104
+ eruby = Erubis::Eruby.new(template)
105
+ output = eruby.result(context)
106
+ rescue Object => e
107
+ raise TemplateError.new(e, template, context)
108
+ end
109
+
110
+ final_tempfile = Tempfile.new(prefix)
111
+ final_tempfile.print(output)
112
+ final_tempfile.close
113
+ final_tempfile
114
+ end
115
+
116
+ def render_template(template, context, prefix)
117
+ self.class.render_template(template, context, prefix)
118
+ end
119
+
120
+ def render_template_file(path, context, prefix)
121
+ template = File.read(path)
122
+ tempfile = render_template(template, context, @package.name)
123
+ tempfile
124
+ end
125
+
126
+ def process(roles) #:nodoc:
127
+ assert_delivery
128
+
129
+ if logger.debug?
130
+ logger.debug "transfer: #{@source} -> #{@destination} for roles: #{roles}\n"
131
+ end
132
+
133
+ unless Sprinkle::OPTIONS[:testing]
134
+ pre = pre_commands(:install)
135
+ unless pre.empty?
136
+ sequence = pre; sequence = sequence.join('; ') if sequence.is_a? Array
137
+ logger.info "#{@package.name} pre-transfer commands: #{sequence} for roles: #{roles}\n"
138
+ @delivery.process @package.name, sequence, roles
139
+ end
140
+
141
+ recursive = @options[:recursive]
142
+
143
+ if options[:render]
144
+ if options[:locals]
145
+ context = {}
146
+ options[:locals].each_pair do |k,v|
147
+ if v.respond_to?(:call)
148
+ context[k] = v.call
149
+ else
150
+ context[k] = v
151
+ end
152
+ end
153
+ else
154
+ context = binding()
155
+ end
156
+
157
+ tempfile = render_template_file(@source, context, @package.name)
158
+ sourcepath = tempfile.path
159
+ logger.info "Rendering template #{@source} to temporary file #{sourcepath}"
160
+ recursive = false
161
+ else
162
+ sourcepath = @source
163
+ end
164
+
165
+ logger.info "--> Transferring #{sourcepath} to #{@destination} for roles: #{roles}"
166
+ @delivery.transfer(@package.name, sourcepath, @destination, roles, recursive)
167
+
168
+ post = post_commands(:install)
169
+ unless post.empty?
170
+ sequence = post; sequence = sequence.join('; ') if sequence.is_a? Array
171
+ logger.info "#{@package.name} post-transfer commands: #{sequence} for roles: #{roles}\n"
172
+ @delivery.process @package.name, sequence, roles
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,15 @@
1
+ module Sprinkle
2
+ module Installers
3
+ class User < Installer
4
+ def initialize(package, username, options, &block)
5
+ super package, &block
6
+ @username=username
7
+ @options =options
8
+ end
9
+ protected
10
+ def install_commands
11
+ "adduser #{@options[:flags]} #{@username}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # = Yum Package Installer
4
+ #
5
+ # The Yum package installer installs RPM packages.
6
+ #
7
+ # == Example Usage
8
+ #
9
+ # Installing the magic_beans RPM via Yum. Its all the craze these days.
10
+ #
11
+ # package :magic_beans do
12
+ # yum 'magic_beans'
13
+ # end
14
+ #
15
+ # You may also specify multiple rpms as an array:
16
+ #
17
+ # package :magic_beans do
18
+ # yum %w(magic_beans magic_sauce)
19
+ # end
20
+ class Yum < Installer
21
+ attr_accessor :packages #:nodoc:
22
+
23
+ def initialize(parent, packages, &block) #:nodoc:
24
+ super parent, &block
25
+ packages = [packages] unless packages.is_a? Array
26
+ @packages = packages
27
+ end
28
+
29
+ protected
30
+
31
+ def install_commands #:nodoc:
32
+ "yum install #{@packages.join(' ')} -y"
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # = Zypper Installer
4
+ #
5
+ # Zypper is a command-line interface to ZYpp system management library.
6
+ # It mostly be used on Suse or OpenSuse.
7
+ #
8
+ # == Example Usage
9
+ #
10
+ # Installing the magic_beans package via Zypper. Its all the craze these days.
11
+ #
12
+ # package :magic_beans do
13
+ # zypper 'magic_beans'
14
+ # end
15
+ #
16
+ # You may also specify multiple packages as an array:
17
+ #
18
+ # package :magic_beans do
19
+ # zypper %w(magic_beans magic_sauce)
20
+ # end
21
+ #
22
+ # or an argument list:
23
+ #
24
+ # package :magic_beans do
25
+ # zypper "magic_beans", "magic_sauce"
26
+ # end
27
+ class Zypper < Installer
28
+ attr_accessor :packages #:nodoc:
29
+
30
+ def initialize(parent, *packages, &block) #:nodoc:
31
+ packages.flatten!
32
+ super parent, &block
33
+ @packages = packages
34
+ end
35
+
36
+ protected
37
+
38
+ def install_commands #:nodoc:
39
+ "zypper -n install -l -R #{@packages.join(' ')}"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,326 @@
1
+ module Sprinkle
2
+ # = Packages
3
+ #
4
+ # A package defines one or more things to provision onto the server.
5
+ # There is a lot of flexibility in a way a package is defined but
6
+ # let me give you a basic example:
7
+ #
8
+ # package :ruby do
9
+ # description 'Ruby MRI'
10
+ # version '1.8.6'
11
+ # apt 'ruby'
12
+ #
13
+ # verify { has_executable 'ruby' }
14
+ # end
15
+ #
16
+ # The above would define a package named 'ruby' and give it a description
17
+ # and explicitly say its version. It is installed via apt and to verify
18
+ # the installation was successful sprinkle will check for the executable
19
+ # 'ruby' being availble. Pretty simple, right?
20
+ #
21
+ # <b>Note:</b> Defining a package does not INSTALL it. To install a
22
+ # package, you must require it in a Sprinkle::Policy block.
23
+ #
24
+ # == Pre-Requirements
25
+ #
26
+ # Most packages have some sort of pre-requisites in order to be installed.
27
+ # Sprinkle allows you to define the requirements of the package, which
28
+ # will be installed before the package itself. An example below:
29
+ #
30
+ # package :rubygems do
31
+ # source 'http://rubyforge.org/rubygems.tgz'
32
+ # requires :ruby
33
+ # end
34
+ #
35
+ # In this case, when rubygems is being installed, Sprinkle will first
36
+ # provision the server with Ruby to make sure the requirements are met.
37
+ # In turn, if ruby has requirements, it installs those first, and so on.
38
+ #
39
+ # == Verifications
40
+ #
41
+ # Most of the time its important to know whether the software you're
42
+ # attempting to install was installed successfully or not. For this,
43
+ # Sprinkle provides verifications. Verifications are one or more blocks
44
+ # which define rules with which Sprinkle can check if it installed
45
+ # the package successfully. If these verification blocks fail, then
46
+ # Sprinkle will gracefully stop the entire process. An example below:
47
+ #
48
+ # package :rubygems do
49
+ # source 'http://rubyforge.org/rubygems.tgz'
50
+ # requires :ruby
51
+ #
52
+ # verify { has_executable 'gem' }
53
+ # end
54
+ #
55
+ # In addition to verifying an installation was successfully, by default
56
+ # Sprinkle runs these verifications <em>before</em> the installation to
57
+ # check if the package is already installed. If the verifications pass
58
+ # before installing the package, it skips the package. To override this
59
+ # behavior, set the -f flag on the sprinkle script or set the
60
+ # :force option to true in Sprinkle::OPTIONS
61
+ #
62
+ # For more information on verifications and to see all the available
63
+ # verifications, see Sprinkle::Verify
64
+ #
65
+ # == Virtual Packages
66
+ #
67
+ # Sometimes, there are multiple packages available for a single task. An
68
+ # example is a database package. It can contain mySQL, postgres, or sqlite!
69
+ # This is where virtual packages come in handy. They are defined as follows:
70
+ #
71
+ # package :sqlite3, :provides => :database do
72
+ # apt 'sqlite3'
73
+ # end
74
+ #
75
+ # The :provides option allows you to reference this package either by :sqlite3
76
+ # or by :database. But whereas the package name is unique, multiple packages may
77
+ # share the same provision. If this is the case, when running Sprinkle, the
78
+ # script will ask you which provision you want to install. At this time, you
79
+ # can only install one.
80
+ #
81
+ # == Meta-Packages
82
+ #
83
+ # A package doesn't require an installer. If you want to define a package which
84
+ # merely encompasses other packages, that is fine too. Example:
85
+ #
86
+ # package :meta do
87
+ # requires :magic_beans
88
+ # requires :magic_sauce
89
+ # end
90
+ #
91
+ #--
92
+ # FIXME: Should probably document recommendations.
93
+ #++
94
+ module Package
95
+ PACKAGES = {}
96
+
97
+ def package(name, metadata = {}, &block)
98
+ package = Package.new(name, metadata, &block)
99
+ PACKAGES[name] = package
100
+
101
+ if package.provides
102
+ (PACKAGES[package.provides] ||= []) << package
103
+ end
104
+
105
+ package
106
+ end
107
+
108
+ class Package #:nodoc:
109
+ include ArbitraryOptions
110
+ attr_accessor :name, :provides, :installers, :dependencies, :recommends, :verifications
111
+
112
+ def initialize(name, metadata = {}, &block)
113
+ raise 'No package name supplied' unless name
114
+
115
+ @name = name
116
+ @provides = metadata[:provides]
117
+ @dependencies = []
118
+ @recommends = []
119
+ @optional = []
120
+ @verifications = []
121
+ @installers = []
122
+ self.instance_eval &block
123
+ end
124
+ def add_user(username, options={}, &block)
125
+ @installers<<Sprinkle::Installers::User.new(self, username, options, &block)
126
+ end
127
+
128
+ def freebsd_pkg(*names, &block)
129
+ @installers << Sprinkle::Installers::FreebsdPkg.new(self, *names, &block)
130
+ end
131
+
132
+ def freebsd_portinstall(port, &block)
133
+ @installers << Sprinkle::Installers::FreebsdPortinstall.new(self, port, &block)
134
+ end
135
+
136
+ def openbsd_pkg(*names, &block)
137
+ @installers << Sprinkle::Installers::OpenbsdPkg.new(self, *names, &block)
138
+ end
139
+
140
+ def opensolaris_pkg(*names, &block)
141
+ @installers << Sprinkle::Installers::OpensolarisPkg.new(self, *names, &block)
142
+ end
143
+
144
+ def bsd_port(port, &block)
145
+ @installers << Sprinkle::Installers::BsdPort.new(self, port, &block)
146
+ end
147
+
148
+ def mac_port(port, &block)
149
+ @installers << Sprinkle::Installers::MacPort.new(self, port, &block)
150
+ end
151
+
152
+ def apt(*names, &block)
153
+ @installers << Sprinkle::Installers::Apt.new(self, *names, &block)
154
+ end
155
+
156
+ def deb(*names, &block)
157
+ @installers << Sprinkle::Installers::Deb.new(self, *names, &block)
158
+ end
159
+
160
+ def rpm(*names, &block)
161
+ @installers << Sprinkle::Installers::Rpm.new(self, *names, &block)
162
+ end
163
+
164
+ def yum(*names, &block)
165
+ @installers << Sprinkle::Installers::Yum.new(self, *names, &block)
166
+ end
167
+
168
+ def zypper(*names, &block)
169
+ @installers << Sprinkle::Installers::Zypper.new(self, *names, &block)
170
+ end
171
+
172
+ def gem(name, options = {}, &block)
173
+ @recommends << :rubygems
174
+ @installers << Sprinkle::Installers::Gem.new(self, name, options, &block)
175
+ end
176
+
177
+ def source(source, options = {}, &block)
178
+ @recommends << :build_essential # Ubuntu/Debian
179
+ @installers << Sprinkle::Installers::Source.new(self, source, options, &block)
180
+ end
181
+
182
+ def binary(source, options = {}, &block)
183
+ @installers << Sprinkle::Installers::Binary.new(self, source, options, &block)
184
+ end
185
+
186
+ def rake(name, options = {}, &block)
187
+ @installers << Sprinkle::Installers::Rake.new(self, name, options, &block)
188
+ end
189
+
190
+ def noop(&block)
191
+ @installers << Sprinkle::Installers::Noop.new(self, name, options, &block)
192
+ end
193
+
194
+ def push_text(text, path, options = {}, &block)
195
+ @installers << Sprinkle::Installers::PushText.new(self, text, path, options, &block)
196
+ end
197
+
198
+ def replace_text(regex, text, path, options={}, &block)
199
+ @installers << Sprinkle::Installers::ReplaceText.new(self, regex, text, path, options, &block)
200
+ end
201
+
202
+ def transfer(source, destination, options = {}, &block)
203
+ @installers << Sprinkle::Installers::Transfer.new(self, source, destination, options, &block)
204
+ end
205
+
206
+ def runner(cmd)
207
+ @installers << Sprinkle::Installers::Runner.new(self, cmd)
208
+ end
209
+
210
+ def verify(description = '', &block)
211
+ @verifications << Sprinkle::Verify.new(self, description, &block)
212
+ end
213
+
214
+ def process(deployment, roles)
215
+ return if meta_package?
216
+
217
+ # Run a pre-test to see if the software is already installed. If so,
218
+ # we can skip it, unless we have the force option turned on!
219
+ unless @verifications.empty? || Sprinkle::OPTIONS[:force]
220
+ begin
221
+ process_verifications(deployment, roles, true)
222
+
223
+ logger.info "--> #{self.name} already installed for roles: #{roles}"
224
+ return
225
+ rescue Sprinkle::VerificationFailed => e
226
+ # Continue
227
+ end
228
+ end
229
+
230
+ @installers.each do |installer|
231
+ installer.defaults(deployment)
232
+ installer.process(roles)
233
+ end
234
+
235
+ process_verifications(deployment, roles)
236
+ end
237
+
238
+ def process_verifications(deployment, roles, pre = false)
239
+ # DWH 20110407 - output command sent to server for better status and debugging
240
+ puts "\n======================= #{self.name} =======================\n\n"
241
+ return if @verifications.blank?
242
+
243
+ if pre
244
+ logger.info "--> Checking if #{self.name} is already installed for roles: #{roles}"
245
+ else
246
+ logger.info "--> Verifying #{self.name} was properly installed for roles: #{roles}"
247
+ end
248
+
249
+ @verifications.each do |v|
250
+ v.defaults(deployment)
251
+ v.process(roles)
252
+ end
253
+ end
254
+
255
+ def requires(*packages)
256
+ @dependencies << packages
257
+ @dependencies.flatten!
258
+ end
259
+
260
+ def recommends(*packages)
261
+ @recommends << packages
262
+ @recommends.flatten!
263
+ end
264
+
265
+ def optional(*packages)
266
+ @optional << packages
267
+ @optional.flatten!
268
+ end
269
+
270
+ def tree(depth = 1, &block)
271
+ packages = []
272
+
273
+ @recommends.each do |dep|
274
+ package = PACKAGES[dep]
275
+ next unless package # skip missing recommended packages as they're allowed to not exist
276
+ block.call(self, package, depth) if block
277
+ packages << package.tree(depth + 1, &block)
278
+ end
279
+
280
+ @dependencies.each do |dep|
281
+ package = PACKAGES[dep]
282
+ package = select_package(dep, package) if package.is_a? Array
283
+
284
+ raise "Package definition not found for key: #{dep}" unless package
285
+ block.call(self, package, depth) if block
286
+ packages << package.tree(depth + 1, &block)
287
+ end
288
+
289
+ packages << self
290
+
291
+ @optional.each do |dep|
292
+ package = PACKAGES[dep]
293
+ next unless package # skip missing optional packages as they're allow to not exist
294
+ block.call(self, package, depth) if block
295
+ packages << package.tree(depth + 1, &block)
296
+ end
297
+
298
+ packages
299
+ end
300
+
301
+ def to_s; @name; end
302
+
303
+ private
304
+
305
+ def select_package(name, packages)
306
+ if packages.size <= 1
307
+ package = packages.first
308
+ else
309
+ package = choose do |menu|
310
+ menu.prompt = "Multiple choices exist for virtual package #{name}"
311
+ menu.choices *packages.collect(&:to_s)
312
+ end
313
+ package = Sprinkle::Package::PACKAGES[package]
314
+ end
315
+
316
+ cloud_info "Selecting #{package.to_s} for virtual package #{name}"
317
+
318
+ package
319
+ end
320
+
321
+ def meta_package?
322
+ @installers.blank?
323
+ end
324
+ end
325
+ end
326
+ end