sprinkle 0.4.2 → 0.5.0.rc1
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/.gitignore +8 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +54 -0
- data/README.markdown +178 -166
- data/Rakefile +4 -28
- data/bin/sprinkle +14 -1
- data/lib/sprinkle.rb +5 -1
- data/lib/sprinkle/actors/actors.rb +20 -5
- data/lib/sprinkle/actors/capistrano.rb +62 -36
- data/lib/sprinkle/actors/dummy.rb +127 -0
- data/lib/sprinkle/actors/local.rb +59 -17
- data/lib/sprinkle/actors/ssh.rb +189 -107
- data/lib/sprinkle/actors/vlad.rb +51 -32
- data/lib/sprinkle/configurable.rb +2 -1
- data/lib/sprinkle/deployment.rb +22 -2
- data/lib/sprinkle/errors/pretty_failure.rb +41 -0
- data/lib/sprinkle/errors/remote_command_failure.rb +24 -0
- data/lib/sprinkle/errors/transfer_failure.rb +28 -0
- data/lib/sprinkle/installers/apt.rb +17 -16
- data/lib/sprinkle/installers/binary.rb +23 -8
- data/lib/sprinkle/installers/brew.rb +17 -10
- data/lib/sprinkle/installers/bsd_port.rb +10 -6
- data/lib/sprinkle/installers/deb.rb +3 -10
- data/lib/sprinkle/installers/freebsd_pkg.rb +5 -11
- data/lib/sprinkle/installers/freebsd_portinstall.rb +8 -2
- data/lib/sprinkle/installers/gem.rb +9 -3
- data/lib/sprinkle/installers/group.rb +28 -4
- data/lib/sprinkle/installers/installer.rb +58 -7
- data/lib/sprinkle/installers/mac_port.rb +13 -6
- data/lib/sprinkle/installers/npm.rb +42 -0
- data/lib/sprinkle/installers/openbsd_pkg.rb +4 -11
- data/lib/sprinkle/installers/opensolaris_pkg.rb +7 -13
- data/lib/sprinkle/installers/package_installer.rb +33 -0
- data/lib/sprinkle/installers/pacman.rb +5 -13
- data/lib/sprinkle/installers/pear.rb +40 -0
- data/lib/sprinkle/installers/push_text.rb +18 -5
- data/lib/sprinkle/installers/rake.rb +7 -2
- data/lib/sprinkle/installers/reconnect.rb +29 -0
- data/lib/sprinkle/installers/replace_text.rb +11 -2
- data/lib/sprinkle/installers/rpm.rb +8 -6
- data/lib/sprinkle/installers/runner.rb +41 -16
- data/lib/sprinkle/installers/smart.rb +6 -17
- data/lib/sprinkle/installers/source.rb +22 -10
- data/lib/sprinkle/installers/thor.rb +7 -0
- data/lib/sprinkle/installers/transfer.rb +62 -41
- data/lib/sprinkle/installers/user.rb +34 -4
- data/lib/sprinkle/installers/yum.rb +10 -10
- data/lib/sprinkle/installers/zypper.rb +4 -15
- data/lib/sprinkle/package.rb +81 -98
- data/lib/sprinkle/policy.rb +11 -4
- data/lib/sprinkle/utility/log_recorder.rb +33 -0
- data/lib/sprinkle/verifiers/directory.rb +1 -1
- data/lib/sprinkle/verifiers/executable.rb +1 -1
- data/lib/sprinkle/verifiers/file.rb +11 -2
- data/lib/sprinkle/verifiers/package.rb +2 -14
- data/lib/sprinkle/verifiers/permission.rb +40 -0
- data/lib/sprinkle/verifiers/symlink.rb +2 -2
- data/lib/sprinkle/verifiers/test.rb +21 -0
- data/lib/sprinkle/verify.rb +3 -3
- data/lib/sprinkle/version.rb +3 -0
- data/spec/fixtures/my_file.txt +1 -0
- data/spec/sprinkle/actors/capistrano_spec.rb +16 -3
- data/spec/sprinkle/actors/local_spec.rb +24 -6
- data/spec/sprinkle/actors/ssh_spec.rb +38 -0
- data/spec/sprinkle/installers/apt_spec.rb +23 -2
- data/spec/sprinkle/installers/binary_spec.rb +22 -14
- data/spec/sprinkle/installers/brew_spec.rb +4 -4
- data/spec/sprinkle/installers/installer_spec.rb +36 -7
- data/spec/sprinkle/installers/npm_spec.rb +16 -0
- data/spec/sprinkle/installers/pear_spec.rb +16 -0
- data/spec/sprinkle/installers/push_text_spec.rb +23 -1
- data/spec/sprinkle/installers/rpm_spec.rb +5 -0
- data/spec/sprinkle/installers/runner_spec.rb +27 -11
- data/spec/sprinkle/installers/smart_spec.rb +60 -0
- data/spec/sprinkle/installers/source_spec.rb +4 -4
- data/spec/sprinkle/installers/transfer_spec.rb +31 -16
- data/spec/sprinkle/package_spec.rb +10 -2
- data/spec/sprinkle/policy_spec.rb +6 -0
- data/spec/sprinkle/verify_spec.rb +18 -4
- data/sprinkle.gemspec +22 -158
- metadata +178 -96
- data/TODO +0 -56
- data/VERSION +0 -1
- data/lib/sprinkle/verifiers/apt.rb +0 -21
- data/lib/sprinkle/verifiers/brew.rb +0 -21
- data/lib/sprinkle/verifiers/rpm.rb +0 -21
- data/lib/sprinkle/verifiers/users_groups.rb +0 -33
@@ -1,4 +1,8 @@
|
|
1
1
|
module Sprinkle
|
2
|
+
# Installers are where the bulk of the work in Sprinkle happens. Installers are
|
3
|
+
# the building blocks of packages. Typically each unique type of install
|
4
|
+
# command has it's own installer class.
|
5
|
+
#
|
2
6
|
module Installers
|
3
7
|
# The base class which all installers must subclass, this class makes
|
4
8
|
# sure all installers share some general features, which are outlined
|
@@ -8,9 +12,16 @@ module Sprinkle
|
|
8
12
|
#
|
9
13
|
# With all installation methods you have the ability to specify multiple
|
10
14
|
# pre/post installation hooks. This gives you the ability to specify
|
11
|
-
# commands to run before and after an installation takes place.
|
12
|
-
#
|
13
|
-
|
15
|
+
# commands to run before and after an installation takes place.
|
16
|
+
# There are three ways to specify a pre/post hook.
|
17
|
+
|
18
|
+
# Note about sudo:
|
19
|
+
# When using the Capistrano actor all commands by default are run using
|
20
|
+
# sudo (unless your Capfile includes "set :use_sudo, false"). If you wish
|
21
|
+
# to use sudo periodically with "set :user_sudo, false" or with an actor
|
22
|
+
# other than Capistrano then you can just append it to your command. Some
|
23
|
+
# installers (transfer) also support a :sudo option, so check each
|
24
|
+
# installer for details.
|
14
25
|
#
|
15
26
|
# First, a single command:
|
16
27
|
#
|
@@ -45,11 +56,37 @@ module Sprinkle
|
|
45
56
|
|
46
57
|
def initialize(package, options = {}, &block) #:nodoc:
|
47
58
|
@package = package
|
48
|
-
@options = options
|
59
|
+
@options = options || {}
|
49
60
|
@pre = {}; @post = {}
|
50
61
|
self.instance_eval(&block) if block
|
51
62
|
end
|
63
|
+
|
64
|
+
class << self
|
65
|
+
def subclasses
|
66
|
+
@subclasses ||= []
|
67
|
+
end
|
68
|
+
|
69
|
+
def api(&block)
|
70
|
+
Sprinkle::Package::Package.class_eval &block
|
71
|
+
end
|
72
|
+
|
73
|
+
def verify_api(&block)
|
74
|
+
Sprinkle::Verify.class_eval &block
|
75
|
+
end
|
52
76
|
|
77
|
+
def inherited(base)
|
78
|
+
subclasses << base
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def sudo_cmd
|
83
|
+
"sudo " if sudo?
|
84
|
+
end
|
85
|
+
|
86
|
+
def sudo?
|
87
|
+
options[:sudo] or package.sudo?
|
88
|
+
end
|
89
|
+
|
53
90
|
def pre(stage, *commands)
|
54
91
|
@pre[stage] ||= []
|
55
92
|
@pre[stage] += commands
|
@@ -61,6 +98,15 @@ module Sprinkle
|
|
61
98
|
@post[stage] += commands
|
62
99
|
@post[stage] += [yield] if block_given?
|
63
100
|
end
|
101
|
+
|
102
|
+
def per_host?
|
103
|
+
return false
|
104
|
+
@per_host
|
105
|
+
end
|
106
|
+
|
107
|
+
# Called right before an installer is exected, can be used for logging
|
108
|
+
# and announcing what is about to happen
|
109
|
+
def announce; end
|
64
110
|
|
65
111
|
def process(roles) #:nodoc:
|
66
112
|
assert_delivery
|
@@ -71,12 +117,11 @@ module Sprinkle
|
|
71
117
|
end
|
72
118
|
|
73
119
|
unless Sprinkle::OPTIONS[:testing]
|
74
|
-
logger.
|
75
|
-
@delivery.
|
120
|
+
logger.debug " --> Running #{self.class.name} for roles: #{roles}"
|
121
|
+
@delivery.install(self, roles, :per_host => per_host?)
|
76
122
|
end
|
77
123
|
end
|
78
124
|
|
79
|
-
protected
|
80
125
|
# More complicated installers that have different stages, and require pre/post commands
|
81
126
|
# within stages can override install_sequence and take complete control of the install
|
82
127
|
# command sequence construction (eg. source based installer).
|
@@ -84,6 +129,12 @@ module Sprinkle
|
|
84
129
|
commands = pre_commands(:install) + [ install_commands ] + post_commands(:install)
|
85
130
|
commands.flatten
|
86
131
|
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
|
135
|
+
def log(t, level=:info)
|
136
|
+
logger.send(level, t)
|
137
|
+
end
|
87
138
|
|
88
139
|
# A concrete installer (subclass of this virtual class) must override this method
|
89
140
|
# and return the commands it needs to run as either a string or an array.
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Sprinkle
|
2
2
|
module Installers
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# The Port installer installs macports ports.
|
3
|
+
# The MacPort installer installs macports ports.
|
6
4
|
#
|
7
5
|
# == Example Usage
|
8
6
|
#
|
@@ -13,17 +11,26 @@ module Sprinkle
|
|
13
11
|
# end
|
14
12
|
#
|
15
13
|
# == Notes
|
14
|
+
#
|
16
15
|
# Before MacPorts packages can be installed, the PATH
|
17
16
|
# environment variable probably has to be changed so
|
18
|
-
#
|
17
|
+
# Sprinkle can find the /opt/local/bin/port executable
|
19
18
|
#
|
20
19
|
# You must set PATH in ~/.ssh/environment on the remote
|
21
20
|
# system and enable 'PermitUserEnvironment yes' in /etc/sshd_config
|
21
|
+
#
|
22
22
|
class MacPort < Installer
|
23
|
+
|
24
|
+
api do
|
25
|
+
def mac_port(port, options={}, &block)
|
26
|
+
install Sprinkle::Installers::MacPort.new(self, port, options, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
23
30
|
attr_accessor :port #:nodoc:
|
24
31
|
|
25
|
-
def initialize(parent, port, &block) #:nodoc:
|
26
|
-
super parent, &block
|
32
|
+
def initialize(parent, port, options = {}, &block) #:nodoc:
|
33
|
+
super parent, options, &block
|
27
34
|
@port = port
|
28
35
|
end
|
29
36
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = Npm package Installed
|
4
|
+
#
|
5
|
+
# Installs an npm module
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# package :magic_beans do
|
10
|
+
# npm 'grunt'
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# verify { has_npm 'grunt' }
|
14
|
+
class Npm < Installer
|
15
|
+
|
16
|
+
attr_accessor :package_name
|
17
|
+
|
18
|
+
api do
|
19
|
+
def npm(package, &block)
|
20
|
+
install Sprinkle::Installers::Npm.new(self, package, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
verify_api do
|
25
|
+
def has_npm(package)
|
26
|
+
@commands << "npm --global list | grep \"#{package}@\""
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(parent, package_name, &block) #:nodoc:
|
31
|
+
super parent, &block
|
32
|
+
@package_name = package_name
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
def install_commands #:nodoc:
|
37
|
+
"npm install --global #{@package_name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Sprinkle
|
2
2
|
module Installers
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# The Pkg package installer installs OpenBSD packages.
|
3
|
+
# The OpenBSD package installer installs OpenBSD packages.
|
6
4
|
#
|
7
5
|
# == Example Usage
|
8
6
|
#
|
@@ -27,14 +25,9 @@ module Sprinkle
|
|
27
25
|
#
|
28
26
|
# For help on PKG_PATH see section 15.2.2 of the OpenBSD FAQ
|
29
27
|
# (http://www.openbsd.org/faq/faq15.html)
|
30
|
-
class OpenbsdPkg <
|
31
|
-
|
32
|
-
|
33
|
-
def initialize(parent, packages, &block) #:nodoc:
|
34
|
-
super parent, &block
|
35
|
-
packages = [packages] unless packages.is_a? Array
|
36
|
-
@packages = packages
|
37
|
-
end
|
28
|
+
class OpenbsdPkg < PackageInstaller
|
29
|
+
|
30
|
+
auto_api
|
38
31
|
|
39
32
|
protected
|
40
33
|
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Sprinkle
|
2
2
|
module Installers
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# The Pkg package installer installs OpenSolaris packages.
|
3
|
+
# The OpenSolaris package installer installs OpenSolaris packages.
|
6
4
|
#
|
7
5
|
# == Example Usage
|
8
6
|
#
|
@@ -21,16 +19,12 @@ module Sprinkle
|
|
21
19
|
# == Note
|
22
20
|
# If you are using capistrano as the deployment method
|
23
21
|
# you will need to add the following lines to your deploy.rb
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
super parent, &block
|
31
|
-
packages = [packages] unless packages.is_a? Array
|
32
|
-
@packages = packages
|
33
|
-
end
|
22
|
+
#
|
23
|
+
# set :sudo, 'pfexec'
|
24
|
+
# set :sudo_prompt, ''
|
25
|
+
class OpensolarisPkg < PackageInstaller
|
26
|
+
|
27
|
+
auto_api
|
34
28
|
|
35
29
|
protected
|
36
30
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# This is a abstract class installer that most all the package installers
|
4
|
+
# inherit from (deb, *BSD pkg, rpm, etc)
|
5
|
+
class PackageInstaller < Installer
|
6
|
+
|
7
|
+
attr_accessor :packages #:nodoc:
|
8
|
+
|
9
|
+
def initialize(parent, *packages, &block) #:nodoc:
|
10
|
+
options = packages.extract_options!
|
11
|
+
super parent, options, &block
|
12
|
+
@packages = [*packages].flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.auto_api
|
16
|
+
method_name = self.to_s.underscore.split("/").last
|
17
|
+
class_name = self.to_s
|
18
|
+
api do
|
19
|
+
method="def #{method_name}(*names, &block)
|
20
|
+
install #{class_name}.new(self, *names, &block)
|
21
|
+
end"
|
22
|
+
eval(method)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# called by subclasses of PackageInstaller
|
27
|
+
def install_package(*names, &block) #:nodoc:
|
28
|
+
install Sprinkle::Installers::class.new(self, *names, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,21 +1,13 @@
|
|
1
1
|
module Sprinkle
|
2
2
|
module Installers
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
super parent, options, &block
|
8
|
-
|
9
|
-
packages = [packages] unless packages.is_a?(Array)
|
10
|
-
packages.flatten!
|
11
|
-
|
12
|
-
|
13
|
-
@packages = packages
|
14
|
-
end
|
3
|
+
# The pacman installer installs Pacman packages
|
4
|
+
class Pacman < PackageInstaller
|
5
|
+
|
6
|
+
auto_api
|
15
7
|
|
16
8
|
protected
|
17
9
|
|
18
|
-
def install_commands
|
10
|
+
def install_commands #:nodoc:
|
19
11
|
"pacman -Sy #{@packages.join(' ')} --no-confirm --needed"
|
20
12
|
end
|
21
13
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# = Pear package installed
|
4
|
+
#
|
5
|
+
# Installs the specified pear package
|
6
|
+
#
|
7
|
+
# == Example Usage
|
8
|
+
#
|
9
|
+
# package :php_stuff do
|
10
|
+
# pear 'PHP_Compat'
|
11
|
+
# verify { has_pear 'PHP_Compat' }
|
12
|
+
# end
|
13
|
+
class Pear < Installer
|
14
|
+
attr_accessor :package_name
|
15
|
+
|
16
|
+
api do
|
17
|
+
def pear(package, &block)
|
18
|
+
install Sprinkle::Installers::Pear.new(self, package, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
verify_api do
|
23
|
+
def has_pear(package)
|
24
|
+
@commands << "pear list | grep \"#{package}\" | grep \"stable\""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(parent, package_name, &block) #:nodoc:
|
29
|
+
super parent, &block
|
30
|
+
@package_name = package_name
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
def install_commands #:nodoc:
|
35
|
+
"pear install --alldeps #{@package_name}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,9 +2,7 @@ module Sprinkle
|
|
2
2
|
module Installers
|
3
3
|
# Beware, strange "installer" coming your way.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# This installer pushes simple configuration into a file.
|
5
|
+
# This push text installer pushes simple configuration into a file.
|
8
6
|
#
|
9
7
|
# == Example Usage
|
10
8
|
#
|
@@ -22,14 +20,29 @@ module Sprinkle
|
|
22
20
|
# end
|
23
21
|
#
|
24
22
|
# A special verify step exists for this very installer
|
25
|
-
# its known as file_contains
|
23
|
+
# its known as +file_contains+, it will test that a file indeed
|
26
24
|
# contains a substring that you send it.
|
27
25
|
#
|
26
|
+
# package :magic_beans do
|
27
|
+
# push_text 'magic_beans', '/etc/apache2/apache2.conf'
|
28
|
+
# verify do
|
29
|
+
# file_contains '/etc/apache2/apache2.conf', 'magic_beans'
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
28
33
|
class PushText < Installer
|
29
34
|
attr_accessor :text, :path #:nodoc:
|
35
|
+
|
36
|
+
api do
|
37
|
+
def push_text(text, path, options = {}, &block)
|
38
|
+
install Sprinkle::Installers::PushText.new(self, text, path, options, &block)
|
39
|
+
end
|
40
|
+
end
|
30
41
|
|
31
42
|
def initialize(parent, text, path, options={}, &block) #:nodoc:
|
32
43
|
super parent, options, &block
|
44
|
+
# by default we would not want to push the same thing over and over
|
45
|
+
options.reverse_merge!(:idempotent => true)
|
33
46
|
@text = text
|
34
47
|
@path = path
|
35
48
|
end
|
@@ -37,7 +50,7 @@ module Sprinkle
|
|
37
50
|
protected
|
38
51
|
|
39
52
|
def install_commands #:nodoc:
|
40
|
-
"#{"#{
|
53
|
+
"#{"#{sudo_cmd}grep \"^#{@text.gsub("'", "'\\\\''").gsub("\n", '\n')}$\" #{@path} || " if option?(:idempotent) }/bin/echo -e '#{@text.gsub("'", "'\\\\''").gsub("\n", '\n')}' |#{sudo_cmd}tee -a #{@path}"
|
41
54
|
end
|
42
55
|
|
43
56
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module Sprinkle
|
2
2
|
module Installers
|
3
|
-
# = Rake Installer
|
4
|
-
#
|
5
3
|
# This installer runs a rake command.
|
6
4
|
#
|
7
5
|
# == Example Usage
|
@@ -20,6 +18,13 @@ module Sprinkle
|
|
20
18
|
# end
|
21
19
|
|
22
20
|
class Rake < Installer
|
21
|
+
|
22
|
+
api do
|
23
|
+
def rake(name, options = {}, &block)
|
24
|
+
install Sprinkle::Installers::Rake.new(self, name, options, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
23
28
|
def initialize(parent, commands, options = {}, &block) #:nodoc:
|
24
29
|
super parent, options, &block
|
25
30
|
@commands = commands
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sprinkle
|
2
|
+
module Installers
|
3
|
+
# Disconnects and reconnects the remote SSH session, you might want to do this
|
4
|
+
# after pushing a file that would affect the local shell environment
|
5
|
+
#
|
6
|
+
# == Example Usage
|
7
|
+
#
|
8
|
+
# package :download_with_proxy do
|
9
|
+
# push_text proxy_config, "/etc/environment", :sudo => true
|
10
|
+
# reconnect
|
11
|
+
# source "http://someurlthatneedstheproxy.com/installer.tar.gz"
|
12
|
+
# end
|
13
|
+
class Reconnect < Installer
|
14
|
+
|
15
|
+
api do
|
16
|
+
def reconnect(options={}, &block)
|
17
|
+
install Sprinkle::Installers::Reconnect.new(self, options, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# :RECONNECT is a symbol that the actors understand to mean to drop
|
22
|
+
# and reestablish any SSH conncetions they have open
|
23
|
+
def install_commands #:nodoc:
|
24
|
+
:RECONNECT
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|