jemmyw-sprinkle 0.2.3
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/CREDITS +21 -0
- data/History.txt +4 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +104 -0
- data/README.txt +241 -0
- data/Rakefile +4 -0
- data/bin/sprinkle +86 -0
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/examples/packages/build_essential.rb +9 -0
- data/examples/packages/databases/mysql.rb +13 -0
- data/examples/packages/databases/sqlite3.rb +16 -0
- data/examples/packages/phusion.rb +55 -0
- data/examples/packages/ruby/rails.rb +9 -0
- data/examples/packages/ruby/ruby.rb +17 -0
- data/examples/packages/ruby/rubygems.rb +17 -0
- data/examples/packages/scm/git.rb +11 -0
- data/examples/packages/scm/subversion.rb +4 -0
- data/examples/packages/servers/apache.rb +15 -0
- data/examples/rails/README +15 -0
- data/examples/rails/deploy.rb +2 -0
- data/examples/rails/packages/database.rb +9 -0
- data/examples/rails/packages/essential.rb +9 -0
- data/examples/rails/packages/rails.rb +28 -0
- data/examples/rails/packages/scm.rb +11 -0
- data/examples/rails/packages/search.rb +11 -0
- data/examples/rails/packages/server.rb +28 -0
- data/examples/rails/rails.rb +73 -0
- data/examples/sprinkle/sprinkle.rb +38 -0
- data/lib/sprinkle/actors/actors.rb +17 -0
- data/lib/sprinkle/actors/capistrano.rb +147 -0
- data/lib/sprinkle/actors/local.rb +50 -0
- data/lib/sprinkle/actors/ssh.rb +81 -0
- data/lib/sprinkle/actors/vlad.rb +65 -0
- data/lib/sprinkle/configurable.rb +31 -0
- data/lib/sprinkle/deployment.rb +77 -0
- data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
- data/lib/sprinkle/extensions/array.rb +5 -0
- data/lib/sprinkle/extensions/blank_slate.rb +5 -0
- data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
- data/lib/sprinkle/extensions/string.rb +10 -0
- data/lib/sprinkle/extensions/symbol.rb +7 -0
- data/lib/sprinkle/installers/apt.rb +52 -0
- data/lib/sprinkle/installers/bsd_port.rb +33 -0
- data/lib/sprinkle/installers/custom.rb +28 -0
- data/lib/sprinkle/installers/deb.rb +38 -0
- data/lib/sprinkle/installers/freebsd_pkg.rb +37 -0
- data/lib/sprinkle/installers/gem.rb +63 -0
- data/lib/sprinkle/installers/installer.rb +120 -0
- data/lib/sprinkle/installers/mac_port.rb +38 -0
- data/lib/sprinkle/installers/openbsd_pkg.rb +47 -0
- data/lib/sprinkle/installers/opensolaris_pkg.rb +43 -0
- data/lib/sprinkle/installers/push_text.rb +45 -0
- data/lib/sprinkle/installers/rake.rb +37 -0
- data/lib/sprinkle/installers/rpm.rb +37 -0
- data/lib/sprinkle/installers/source.rb +179 -0
- data/lib/sprinkle/installers/yum.rb +37 -0
- data/lib/sprinkle/package.rb +293 -0
- data/lib/sprinkle/policy.rb +126 -0
- data/lib/sprinkle/script.rb +23 -0
- data/lib/sprinkle/verifiers/directory.rb +16 -0
- data/lib/sprinkle/verifiers/dpkg.rb +14 -0
- data/lib/sprinkle/verifiers/executable.rb +36 -0
- data/lib/sprinkle/verifiers/file.rb +26 -0
- data/lib/sprinkle/verifiers/process.rb +21 -0
- data/lib/sprinkle/verifiers/ruby.rb +25 -0
- data/lib/sprinkle/verifiers/symlink.rb +30 -0
- data/lib/sprinkle/verifiers/user.rb +11 -0
- data/lib/sprinkle/verify.rb +114 -0
- data/lib/sprinkle/version.rb +9 -0
- data/lib/sprinkle.rb +32 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/sprinkle/actors/capistrano_spec.rb +194 -0
- data/spec/sprinkle/actors/local_spec.rb +29 -0
- data/spec/sprinkle/configurable_spec.rb +46 -0
- data/spec/sprinkle/deployment_spec.rb +80 -0
- data/spec/sprinkle/extensions/array_spec.rb +19 -0
- data/spec/sprinkle/extensions/string_spec.rb +21 -0
- data/spec/sprinkle/installers/apt_spec.rb +70 -0
- data/spec/sprinkle/installers/bsd_port_spec.rb +42 -0
- data/spec/sprinkle/installers/custom_spec.rb +29 -0
- data/spec/sprinkle/installers/freebsd_pkg_spec.rb +49 -0
- data/spec/sprinkle/installers/gem_spec.rb +91 -0
- data/spec/sprinkle/installers/installer_spec.rb +151 -0
- data/spec/sprinkle/installers/mac_port_spec.rb +42 -0
- data/spec/sprinkle/installers/openbsd_pkg_spec.rb +49 -0
- data/spec/sprinkle/installers/opensolaris_pkg_spec.rb +49 -0
- data/spec/sprinkle/installers/push_text_spec.rb +55 -0
- data/spec/sprinkle/installers/rake_spec.rb +29 -0
- data/spec/sprinkle/installers/rpm_spec.rb +50 -0
- data/spec/sprinkle/installers/source_spec.rb +331 -0
- data/spec/sprinkle/installers/yum_spec.rb +49 -0
- data/spec/sprinkle/package_spec.rb +452 -0
- data/spec/sprinkle/policy_spec.rb +133 -0
- data/spec/sprinkle/script_spec.rb +51 -0
- data/spec/sprinkle/sprinkle_spec.rb +25 -0
- data/spec/sprinkle/verify_spec.rb +185 -0
- data/sprinkle.gemspec +45 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- metadata +199 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# Beware, strange "installer" coming your way.
|
4
|
+
#
|
5
|
+
# = Text configuration installer
|
6
|
+
#
|
7
|
+
# This installer pushes simple configuration into a file.
|
8
|
+
#
|
9
|
+
# == Example Usage
|
10
|
+
#
|
11
|
+
# Installing magic_beans into apache2.conf
|
12
|
+
#
|
13
|
+
# package :magic_beans do
|
14
|
+
# push_text 'magic_beans', '/etc/apache2/apache2.conf'
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# If you user has access to 'sudo' and theres a file that requires
|
18
|
+
# priveledges, you can pass :sudo => true
|
19
|
+
#
|
20
|
+
# package :magic_beans do
|
21
|
+
# push_text 'magic_beans', '/etc/apache2/apache2.conf', :sudo => true
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# A special verify step exists for this very installer
|
25
|
+
# its known as file_contains, it will test that a file indeed
|
26
|
+
# contains a substring that you send it.
|
27
|
+
#
|
28
|
+
class PushText < Installer
|
29
|
+
attr_accessor :text, :path #:nodoc:
|
30
|
+
|
31
|
+
def initialize(parent, text, path, options={}, &block) #:nodoc:
|
32
|
+
super parent, options, &block
|
33
|
+
@text = text
|
34
|
+
@path = path
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def install_commands #:nodoc:
|
40
|
+
"echo '#{@text}' |#{'sudo' if option?(:sudo)} tee -a #{@path}"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = Rake Installer
|
4
|
+
#
|
5
|
+
# This installer runs a rake command.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# The following example runs the command "rake spec" on
|
10
|
+
# the remote server.
|
11
|
+
#
|
12
|
+
# package :spec do
|
13
|
+
# rake 'spec'
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# Specify a Rakefile with the :rakefile option.
|
17
|
+
#
|
18
|
+
# package :spec, :rakefile => "/var/setup/Rakefile" do
|
19
|
+
# rake 'spec'
|
20
|
+
# end
|
21
|
+
|
22
|
+
class Rake < Installer
|
23
|
+
def initialize(parent, commands, options = {}, &block) #:nodoc:
|
24
|
+
super parent, options, &block
|
25
|
+
@commands = commands.to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def install_commands #:nodoc:
|
31
|
+
file = @options[:rakefile] ? "-f #{@options[:rakefile]} " : ""
|
32
|
+
"rake #{file}#{@commands.join(' ')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = RPM Package Installer
|
4
|
+
#
|
5
|
+
# The RPM package installer installs RPM packages.
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# Installing the magic_beans RPM. Its all the craze these days.
|
10
|
+
#
|
11
|
+
# package :magic_beans do
|
12
|
+
# rpm 'magic_beans'
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# You may also specify multiple rpms as an array:
|
16
|
+
#
|
17
|
+
# package :magic_beans do
|
18
|
+
# rpm %w(magic_beans magic_sauce)
|
19
|
+
# end
|
20
|
+
class Rpm < 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
|
+
"rpm -Uvh #{@packages.join(' ')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = Source Package Installer
|
4
|
+
#
|
5
|
+
# The source package installer installs software from source.
|
6
|
+
# It handles downloading, extracting, configuring, building,
|
7
|
+
# and installing software.
|
8
|
+
#
|
9
|
+
# == Configuration Options
|
10
|
+
#
|
11
|
+
# The source installer has many configuration options:
|
12
|
+
# * <b>prefix</b> - The prefix directory that is configured to.
|
13
|
+
# * <b>archives</b> - The location all the files are downloaded to.
|
14
|
+
# * <b>builds</b> - The directory the package is extracted to to configure and install
|
15
|
+
#
|
16
|
+
# == Pre/Post Hooks
|
17
|
+
#
|
18
|
+
# The source installer defines a myriad of new stages which can be hooked into:
|
19
|
+
# * <b>prepare</b> - Prepare is the stage which all the prefix, archives, and build directories are made.
|
20
|
+
# * <b>download</b> - Download is the stage which the software package is downloaded.
|
21
|
+
# * <b>extract</b> - Extract is the stage which the software package is extracted.
|
22
|
+
# * <b>configure</b> - Configure is the stage which the ./configure script is run.
|
23
|
+
# * <b>build</b> - Build is the stage in which `make` is called.
|
24
|
+
# * <b>install</b> - Install is the stage which `make install` is called.
|
25
|
+
#
|
26
|
+
# == Example Usage
|
27
|
+
#
|
28
|
+
# First, a simple package, no configuration:
|
29
|
+
#
|
30
|
+
# package :magic_beans do
|
31
|
+
# source 'http://magicbeansland.com/latest-1.1.1.tar.gz'
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# Second, specifying exactly where I want my files:
|
35
|
+
#
|
36
|
+
# package :magic_beans do
|
37
|
+
# source 'http://magicbeansland.com/latest-1.1.1.tar.gz' do
|
38
|
+
# prefix '/usr/local'
|
39
|
+
# archives '/tmp'
|
40
|
+
# builds '/tmp/builds'
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# Third, specifying some hooks:
|
45
|
+
#
|
46
|
+
# package :magic_beans do
|
47
|
+
# source 'http://magicbeansland.com/latest-1.1.1.tar.gz' do
|
48
|
+
# prefix '/usr/local'
|
49
|
+
#
|
50
|
+
# pre :prepare { 'echo "Here we go folks."' }
|
51
|
+
# post :extract { 'echo "I believe..."' }
|
52
|
+
# pre :build { 'echo "Cross your fingers!"' }
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# As you can see, setting options is as simple as creating a
|
57
|
+
# block and calling the option as a method with the value as
|
58
|
+
# its parameter.
|
59
|
+
class Source < Installer
|
60
|
+
attr_accessor :source #:nodoc:
|
61
|
+
|
62
|
+
def initialize(parent, source, options = {}, &block) #:nodoc:
|
63
|
+
@source = source
|
64
|
+
super parent, options, &block
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def install_sequence #:nodoc:
|
70
|
+
prepare + download + extract + configure + build + install
|
71
|
+
end
|
72
|
+
|
73
|
+
%w( prepare download extract configure build install ).each do |stage|
|
74
|
+
define_method stage do
|
75
|
+
pre_commands(stage.to_sym) + self.send("#{stage}_commands") + post_commands(stage.to_sym)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepare_commands #:nodoc:
|
80
|
+
raise 'No installation area defined' unless @options[:prefix]
|
81
|
+
raise 'No build area defined' unless @options[:builds]
|
82
|
+
raise 'No source download area defined' unless @options[:archives]
|
83
|
+
|
84
|
+
[ "mkdir -p #{@options[:prefix]}",
|
85
|
+
"mkdir -p #{@options[:builds]}",
|
86
|
+
"mkdir -p #{@options[:archives]}" ]
|
87
|
+
end
|
88
|
+
|
89
|
+
def download_commands #:nodoc:
|
90
|
+
[ "wget -cq --directory-prefix='#{@options[:archives]}' #{@source}" ]
|
91
|
+
end
|
92
|
+
|
93
|
+
def extract_commands #:nodoc:
|
94
|
+
[ "bash -c 'cd #{@options[:builds]} && #{extract_command} #{@options[:archives]}/#{archive_name}'" ]
|
95
|
+
end
|
96
|
+
|
97
|
+
def configure_commands #:nodoc:
|
98
|
+
return [] if custom_install?
|
99
|
+
|
100
|
+
command = "bash -c 'cd #{build_dir} && ./configure --prefix=#{@options[:prefix]} "
|
101
|
+
|
102
|
+
extras = {
|
103
|
+
:enable => '--enable', :disable => '--disable',
|
104
|
+
:with => '--with', :without => '--without'
|
105
|
+
}
|
106
|
+
|
107
|
+
extras.inject(command) { |m, (k, v)| m << create_options(k, v) if options[k]; m }
|
108
|
+
|
109
|
+
[ command << " > #{@package.name}-configure.log 2>&1'" ]
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_commands #:nodoc:
|
113
|
+
return [] if custom_install?
|
114
|
+
[ "bash -c 'cd #{build_dir} && make > #{@package.name}-build.log 2>&1'" ]
|
115
|
+
end
|
116
|
+
|
117
|
+
def install_commands #:nodoc:
|
118
|
+
return custom_install_commands if custom_install?
|
119
|
+
[ "bash -c 'cd #{build_dir} && make install > #{@package.name}-install.log 2>&1'" ]
|
120
|
+
end
|
121
|
+
|
122
|
+
def custom_install? #:nodoc:
|
123
|
+
!! @options[:custom_install]
|
124
|
+
end
|
125
|
+
|
126
|
+
# REVISIT: must be better processing of custom install commands somehow? use splat operator?
|
127
|
+
def custom_install_commands #:nodoc:
|
128
|
+
dress @options[:custom_install], :install
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
# dress is overriden from the base Sprinkle::Installers::Installer class so that the command changes
|
134
|
+
# directory to the build directory first. Also, the result of the command is logged.
|
135
|
+
def dress(commands, stage)
|
136
|
+
commands.collect { |command| "bash -c 'cd #{build_dir} && #{command} >> #{@package.name}-#{stage}.log 2>&1'" }
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def create_options(key, prefix) #:nodoc:
|
142
|
+
@options[key].inject(' ') { |m, option| m << "#{prefix}-#{option} "; m }
|
143
|
+
end
|
144
|
+
|
145
|
+
def extract_command #:nodoc:
|
146
|
+
case @source
|
147
|
+
when /(tar.gz)|(tgz)$/
|
148
|
+
'tar xzf'
|
149
|
+
when /(tar.bz2)|(tb2)$/
|
150
|
+
'tar xjf'
|
151
|
+
when /tar$/
|
152
|
+
'tar xf'
|
153
|
+
when /zip$/
|
154
|
+
'unzip'
|
155
|
+
else
|
156
|
+
raise "Unknown source archive format: #{archive_name}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def archive_name #:nodoc:
|
161
|
+
name = @source.split('/').last
|
162
|
+
raise "Unable to determine archive name for source: #{source}, please update code knowledge" unless name
|
163
|
+
name
|
164
|
+
end
|
165
|
+
|
166
|
+
def build_dir #:nodoc:
|
167
|
+
"#{@options[:builds]}/#{options[:custom_dir] || base_dir}"
|
168
|
+
end
|
169
|
+
|
170
|
+
def base_dir #:nodoc:
|
171
|
+
if @source.split('/').last =~ /(.*)\.(tar\.gz|tgz|tar\.bz2|tb2)/
|
172
|
+
return $1
|
173
|
+
end
|
174
|
+
raise "Unknown base path for source archive: #{@source}, please update code knowledge"
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
179
|
+
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,293 @@
|
|
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, :operations, :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
|
+
@verifications = []
|
120
|
+
@operations = []
|
121
|
+
self.instance_eval(&block)
|
122
|
+
end
|
123
|
+
|
124
|
+
def freebsd_pkg(*names, &block)
|
125
|
+
@operations << Sprinkle::Installers::FreebsdPkg.new(self, *names, &block)
|
126
|
+
end
|
127
|
+
|
128
|
+
def openbsd_pkg(*names, &block)
|
129
|
+
@operations << Sprinkle::Installers::OpenbsdPkg.new(self, *names, &block)
|
130
|
+
end
|
131
|
+
|
132
|
+
def opensolaris_pkg(*names, &block)
|
133
|
+
@operations << Sprinkle::Installers::OpensolarisPkg.new(self, *names, &block)
|
134
|
+
end
|
135
|
+
|
136
|
+
def bsd_port(port, &block)
|
137
|
+
@operations << Sprinkle::Installers::BsdPort.new(self, port, &block)
|
138
|
+
end
|
139
|
+
|
140
|
+
def mac_port(port, &block)
|
141
|
+
@operations << Sprinkle::Installers::MacPort.new(self, port, &block)
|
142
|
+
end
|
143
|
+
|
144
|
+
def apt(*names, &block)
|
145
|
+
@operations << Sprinkle::Installers::Apt.new(self, *names, &block)
|
146
|
+
end
|
147
|
+
|
148
|
+
def deb(*names, &block)
|
149
|
+
@operations << Sprinkle::Installers::Deb.new(self, *names, &block)
|
150
|
+
end
|
151
|
+
|
152
|
+
def rpm(*names, &block)
|
153
|
+
@operations << Sprinkle::Installers::Rpm.new(self, *names, &block)
|
154
|
+
end
|
155
|
+
|
156
|
+
def yum(*names, &block)
|
157
|
+
@operations << Sprinkle::Installers::Yum.new(self, *names, &block)
|
158
|
+
end
|
159
|
+
|
160
|
+
def gem(name, options = {}, &block)
|
161
|
+
@recommends << :rubygems
|
162
|
+
@operations << Sprinkle::Installers::Gem.new(self, name, options, &block)
|
163
|
+
end
|
164
|
+
|
165
|
+
def source(source, options = {}, &block)
|
166
|
+
@recommends << :build_essential # Ubuntu/Debian
|
167
|
+
@operations << Sprinkle::Installers::Source.new(self, source, options, &block)
|
168
|
+
end
|
169
|
+
|
170
|
+
def rake(name, options = {}, &block)
|
171
|
+
@operations << Sprinkle::Installers::Rake.new(self, name, options, &block)
|
172
|
+
end
|
173
|
+
|
174
|
+
def push_text(text, path, options = {}, &block)
|
175
|
+
@installer = Sprinkle::Installers::PushText.new(self, text, path, options, &block)
|
176
|
+
end
|
177
|
+
|
178
|
+
def custom(command, &block)
|
179
|
+
@installer = Sprinkle::Installers::Custom.new(self, command, &block)
|
180
|
+
end
|
181
|
+
|
182
|
+
def verify(description = '', &block)
|
183
|
+
@verifications << Sprinkle::Verify.new(self, description, &block)
|
184
|
+
end
|
185
|
+
|
186
|
+
def verify(description = '', &block)
|
187
|
+
@verifications << Sprinkle::Verify.new(self, description, &block)
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
def process(deployment, roles)
|
192
|
+
return if meta_package?
|
193
|
+
|
194
|
+
roles = [roles].flatten
|
195
|
+
roles.each do |role|
|
196
|
+
servers = deployment.find_servers(role)
|
197
|
+
|
198
|
+
servers.each do |server|
|
199
|
+
# Run a pre-test to see if the software is already installed. If so,
|
200
|
+
# we can skip it, unless we have the force option turned on!
|
201
|
+
unless @verifications.empty? || Sprinkle::OPTIONS[:force]
|
202
|
+
begin
|
203
|
+
process_verifications(deployment, server, true)
|
204
|
+
logger.info "--> #{self.name} already installed for server: #{server}"
|
205
|
+
next
|
206
|
+
rescue Sprinkle::VerificationFailed => e
|
207
|
+
# Continue
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
@operations.each do |installer|
|
212
|
+
installer.defaults(deployment) if installer.responds_to?(:defaults)
|
213
|
+
installer.process(server) if installer.responds_to?(:process)
|
214
|
+
end
|
215
|
+
|
216
|
+
process_verifications(deployment, server)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def process_verifications(deployment, server, pre = false)
|
222
|
+
return if @verifications.blank?
|
223
|
+
|
224
|
+
if pre
|
225
|
+
logger.info "--> Checking if #{self.name} is already installed for server: #{server}"
|
226
|
+
else
|
227
|
+
logger.info "--> Verifying #{self.name} was properly installed for server: #{server}"
|
228
|
+
end
|
229
|
+
|
230
|
+
@verifications.each do |v|
|
231
|
+
v.defaults(deployment)
|
232
|
+
v.process(server)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def requires(*packages)
|
237
|
+
@dependencies << packages
|
238
|
+
@dependencies.flatten!
|
239
|
+
end
|
240
|
+
|
241
|
+
def recommends(*packages)
|
242
|
+
@recommends << packages
|
243
|
+
@recommends.flatten!
|
244
|
+
end
|
245
|
+
|
246
|
+
def tree(depth = 1, &block)
|
247
|
+
packages = []
|
248
|
+
|
249
|
+
@recommends.each do |dep|
|
250
|
+
package = PACKAGES[dep]
|
251
|
+
next unless package # skip missing recommended packages as they can be optional
|
252
|
+
block.call(self, package, depth) if block
|
253
|
+
packages << package.tree(depth + 1, &block)
|
254
|
+
end
|
255
|
+
|
256
|
+
@dependencies.each do |dep|
|
257
|
+
package = PACKAGES[dep]
|
258
|
+
package = select_package(dep, package) if package.is_a? Array
|
259
|
+
|
260
|
+
raise "Package definition not found for key: #{dep}" unless package
|
261
|
+
block.call(self, package, depth) if block
|
262
|
+
packages << package.tree(depth + 1, &block)
|
263
|
+
end
|
264
|
+
|
265
|
+
packages << self
|
266
|
+
end
|
267
|
+
|
268
|
+
def to_s; @name; end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def select_package(name, packages)
|
273
|
+
if packages.size <= 1
|
274
|
+
package = packages.first
|
275
|
+
else
|
276
|
+
package = choose do |menu|
|
277
|
+
menu.prompt = "Multiple choices exist for virtual package #{name}"
|
278
|
+
menu.choices *packages.collect(&:to_s)
|
279
|
+
end
|
280
|
+
package = Sprinkle::Package::PACKAGES[package]
|
281
|
+
end
|
282
|
+
|
283
|
+
cloud_info "Selecting #{package.to_s} for virtual package #{name}"
|
284
|
+
|
285
|
+
package
|
286
|
+
end
|
287
|
+
|
288
|
+
def meta_package?
|
289
|
+
@operations.empty?
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|