sprinkle 0.4.2 → 0.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/.gitignore +8 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +54 -0
  4. data/README.markdown +178 -166
  5. data/Rakefile +4 -28
  6. data/bin/sprinkle +14 -1
  7. data/lib/sprinkle.rb +5 -1
  8. data/lib/sprinkle/actors/actors.rb +20 -5
  9. data/lib/sprinkle/actors/capistrano.rb +62 -36
  10. data/lib/sprinkle/actors/dummy.rb +127 -0
  11. data/lib/sprinkle/actors/local.rb +59 -17
  12. data/lib/sprinkle/actors/ssh.rb +189 -107
  13. data/lib/sprinkle/actors/vlad.rb +51 -32
  14. data/lib/sprinkle/configurable.rb +2 -1
  15. data/lib/sprinkle/deployment.rb +22 -2
  16. data/lib/sprinkle/errors/pretty_failure.rb +41 -0
  17. data/lib/sprinkle/errors/remote_command_failure.rb +24 -0
  18. data/lib/sprinkle/errors/transfer_failure.rb +28 -0
  19. data/lib/sprinkle/installers/apt.rb +17 -16
  20. data/lib/sprinkle/installers/binary.rb +23 -8
  21. data/lib/sprinkle/installers/brew.rb +17 -10
  22. data/lib/sprinkle/installers/bsd_port.rb +10 -6
  23. data/lib/sprinkle/installers/deb.rb +3 -10
  24. data/lib/sprinkle/installers/freebsd_pkg.rb +5 -11
  25. data/lib/sprinkle/installers/freebsd_portinstall.rb +8 -2
  26. data/lib/sprinkle/installers/gem.rb +9 -3
  27. data/lib/sprinkle/installers/group.rb +28 -4
  28. data/lib/sprinkle/installers/installer.rb +58 -7
  29. data/lib/sprinkle/installers/mac_port.rb +13 -6
  30. data/lib/sprinkle/installers/npm.rb +42 -0
  31. data/lib/sprinkle/installers/openbsd_pkg.rb +4 -11
  32. data/lib/sprinkle/installers/opensolaris_pkg.rb +7 -13
  33. data/lib/sprinkle/installers/package_installer.rb +33 -0
  34. data/lib/sprinkle/installers/pacman.rb +5 -13
  35. data/lib/sprinkle/installers/pear.rb +40 -0
  36. data/lib/sprinkle/installers/push_text.rb +18 -5
  37. data/lib/sprinkle/installers/rake.rb +7 -2
  38. data/lib/sprinkle/installers/reconnect.rb +29 -0
  39. data/lib/sprinkle/installers/replace_text.rb +11 -2
  40. data/lib/sprinkle/installers/rpm.rb +8 -6
  41. data/lib/sprinkle/installers/runner.rb +41 -16
  42. data/lib/sprinkle/installers/smart.rb +6 -17
  43. data/lib/sprinkle/installers/source.rb +22 -10
  44. data/lib/sprinkle/installers/thor.rb +7 -0
  45. data/lib/sprinkle/installers/transfer.rb +62 -41
  46. data/lib/sprinkle/installers/user.rb +34 -4
  47. data/lib/sprinkle/installers/yum.rb +10 -10
  48. data/lib/sprinkle/installers/zypper.rb +4 -15
  49. data/lib/sprinkle/package.rb +81 -98
  50. data/lib/sprinkle/policy.rb +11 -4
  51. data/lib/sprinkle/utility/log_recorder.rb +33 -0
  52. data/lib/sprinkle/verifiers/directory.rb +1 -1
  53. data/lib/sprinkle/verifiers/executable.rb +1 -1
  54. data/lib/sprinkle/verifiers/file.rb +11 -2
  55. data/lib/sprinkle/verifiers/package.rb +2 -14
  56. data/lib/sprinkle/verifiers/permission.rb +40 -0
  57. data/lib/sprinkle/verifiers/symlink.rb +2 -2
  58. data/lib/sprinkle/verifiers/test.rb +21 -0
  59. data/lib/sprinkle/verify.rb +3 -3
  60. data/lib/sprinkle/version.rb +3 -0
  61. data/spec/fixtures/my_file.txt +1 -0
  62. data/spec/sprinkle/actors/capistrano_spec.rb +16 -3
  63. data/spec/sprinkle/actors/local_spec.rb +24 -6
  64. data/spec/sprinkle/actors/ssh_spec.rb +38 -0
  65. data/spec/sprinkle/installers/apt_spec.rb +23 -2
  66. data/spec/sprinkle/installers/binary_spec.rb +22 -14
  67. data/spec/sprinkle/installers/brew_spec.rb +4 -4
  68. data/spec/sprinkle/installers/installer_spec.rb +36 -7
  69. data/spec/sprinkle/installers/npm_spec.rb +16 -0
  70. data/spec/sprinkle/installers/pear_spec.rb +16 -0
  71. data/spec/sprinkle/installers/push_text_spec.rb +23 -1
  72. data/spec/sprinkle/installers/rpm_spec.rb +5 -0
  73. data/spec/sprinkle/installers/runner_spec.rb +27 -11
  74. data/spec/sprinkle/installers/smart_spec.rb +60 -0
  75. data/spec/sprinkle/installers/source_spec.rb +4 -4
  76. data/spec/sprinkle/installers/transfer_spec.rb +31 -16
  77. data/spec/sprinkle/package_spec.rb +10 -2
  78. data/spec/sprinkle/policy_spec.rb +6 -0
  79. data/spec/sprinkle/verify_spec.rb +18 -4
  80. data/sprinkle.gemspec +22 -158
  81. metadata +178 -96
  82. data/TODO +0 -56
  83. data/VERSION +0 -1
  84. data/lib/sprinkle/verifiers/apt.rb +0 -21
  85. data/lib/sprinkle/verifiers/brew.rb +0 -21
  86. data/lib/sprinkle/verifiers/rpm.rb +0 -21
  87. data/lib/sprinkle/verifiers/users_groups.rb +0 -33
@@ -25,6 +25,12 @@ module Sprinkle
25
25
  #
26
26
  class ReplaceText < Installer
27
27
  attr_accessor :regex, :text, :path #:nodoc:
28
+
29
+ api do
30
+ def replace_text(regex, text, path, options={}, &block)
31
+ install Sprinkle::Installers::ReplaceText.new(self, regex, text, path, options, &block)
32
+ end
33
+ end
28
34
 
29
35
  def initialize(parent, regex, text, path, options={}, &block) #:nodoc:
30
36
  super parent, options, &block
@@ -32,11 +38,14 @@ module Sprinkle
32
38
  @text = text
33
39
  @path = path
34
40
  end
41
+
42
+ def announce
43
+ log "--> Replace '#{@regex}' with '#{@text}' in file #{@path}"
44
+ end
35
45
 
36
46
  protected
37
-
47
+
38
48
  def install_commands #:nodoc:
39
- logger.info "--> Replace '#{@regex}' with '#{@text}' in file #{@path}"
40
49
  "#{'sudo ' if option?(:sudo)}sed -i 's/#{@regex.gsub("'", "'\\\\''").gsub("/", "\\\\/").gsub("\n", '\n')}/#{@text.gsub("'", "'\\\\''").gsub("/", "\\\\/").gsub("\n", '\n')}/g' #{@path}"
41
50
  end
42
51
 
@@ -10,6 +10,7 @@ module Sprinkle
10
10
  #
11
11
  # package :magic_beans do
12
12
  # rpm 'magic_beans'
13
+ # verify { has_rpm 'magic_beans' }
13
14
  # end
14
15
  #
15
16
  # You may also specify multiple rpms as an array:
@@ -17,13 +18,14 @@ module Sprinkle
17
18
  # package :magic_beans do
18
19
  # rpm %w(magic_beans magic_sauce)
19
20
  # end
20
- class Rpm < Installer
21
- attr_accessor :packages #:nodoc:
21
+ class Rpm < PackageInstaller
22
22
 
23
- def initialize(parent, packages, &block) #:nodoc:
24
- super parent, &block
25
- packages = [packages] unless packages.is_a? Array
26
- @packages = packages
23
+ auto_api
24
+
25
+ verify_api do
26
+ def has_rpm(package)
27
+ @commands << "rpm -qa | grep #{package}"
28
+ end
27
29
  end
28
30
 
29
31
  protected
@@ -1,18 +1,43 @@
1
1
  module Sprinkle
2
- module Installers
3
- class Runner < Installer
4
- attr_accessor :cmd #:nodoc:
5
-
6
- def initialize(parent, cmd, &block) #:nodoc:
7
- super parent, {}, &block
8
- @cmd = cmd
9
- end
10
-
11
- protected
12
-
13
- def install_commands #:nodoc:
14
- @cmd
15
- end
16
- end
17
- end
2
+ module Installers
3
+ # The runner installer is great for running a simple command.
4
+ #
5
+ # == Example Usage
6
+ #
7
+ # package :magic_beans do
8
+ # runner "make world"
9
+ # end
10
+ #
11
+ # You can also pass multiple commands as arguments or an array.
12
+ #
13
+ # package :magic_beans do
14
+ # runner "make world", "destroy world"
15
+ # runner [ "make world", "destroy world" ]
16
+ # end
17
+ #
18
+ class Runner < Installer
19
+
20
+ api do
21
+ def runner(*cmds, &block)
22
+ options = cmds.extract_options!
23
+ install Sprinkle::Installers::Runner.new(self, cmds, options, &block)
24
+ end
25
+ end
26
+
27
+ attr_accessor :cmds #:nodoc:
28
+ def initialize(parent, cmds, options = {}, &block) #:nodoc:
29
+ super parent, options, &block
30
+ @cmds = [*cmds].flatten
31
+ raise "you need to specify a command" if cmds.nil?
32
+ end
33
+
34
+ protected
35
+
36
+ def install_commands #:nodoc:
37
+ sudo_cmd ?
38
+ @cmds.map { |cmd| "#{sudo_cmd}#{cmd}"} :
39
+ @cmds
40
+ end
41
+ end
42
+ end
18
43
  end
@@ -1,12 +1,11 @@
1
1
  module Sprinkle
2
2
  module Installers
3
- class Smart < Installer
4
- attr_accessor :packages #:nodoc:
5
-
6
- def initialize(parent, packages, &block) #:nodoc:
7
- super parent, &block
8
- packages = [packages] unless packages.is_a? Array
9
- @packages = packages
3
+ class Smart < PackageInstaller
4
+
5
+ api do
6
+ def smart(*names, &block)
7
+ install Sprinkle::Installers::Smart.new(self, *names, &block)
8
+ end
10
9
  end
11
10
 
12
11
  protected
@@ -16,14 +15,4 @@ module Sprinkle
16
15
  end
17
16
  end
18
17
  end
19
- end
20
-
21
- module Sprinkle
22
- module Package
23
- class Package
24
- def smart(*names, &block)
25
- @installer = Sprinkle::Installers::Smart.new(self, *names, &block)
26
- end
27
- end
28
- end
29
18
  end
@@ -62,24 +62,40 @@ module Sprinkle
62
62
  # end
63
63
  # end
64
64
  #
65
+ # Fifth, specifying a custom directory where the archive actually is extracted to:
66
+ #
67
+ # package :ruby_build do
68
+ # source 'https://github.com/sstephenson/ruby-build/archive/v20130227.tar.gz' do
69
+ # custom_dir 'ruby-build-20130227'
70
+ # custom_install './install.sh'
71
+ # end
72
+ # end
73
+ #
65
74
  # As you can see, setting options is as simple as creating a
66
75
  # block and calling the option as a method with the value as
67
76
  # its parameter.
68
77
 
69
78
  class Source < Installer
70
79
  attr_accessor :source #:nodoc:
80
+
81
+ api do
82
+ def source(source, options = {}, &block)
83
+ @recommends << :build_essential # Ubuntu/Debian
84
+ install Sprinkle::Installers::Source.new(self, source, options, &block)
85
+ end
86
+ end
71
87
 
72
88
  def initialize(parent, source, options = {}, &block) #:nodoc:
73
- @source = source
74
89
  super parent, options, &block
90
+ @source = source
91
+ end
92
+
93
+ def install_sequence #:nodoc:
94
+ prepare + download + extract + configure + build + install
75
95
  end
76
96
 
77
97
  protected
78
98
 
79
- def install_sequence #:nodoc:
80
- prepare + download + extract + configure + build + install
81
- end
82
-
83
99
  %w( prepare download extract configure build install ).each do |stage|
84
100
  define_method stage do
85
101
  pre_commands(stage.to_sym) + self.send("#{stage}_commands") + post_commands(stage.to_sym)
@@ -97,11 +113,7 @@ module Sprinkle
97
113
  end
98
114
 
99
115
  def download_commands #:nodoc:
100
- if File.exist? @source
101
- [ "cp #{@source} #{@options[:archives].first}/#{archive_name}" ]
102
- else
103
- [ "wget -cq -O '#{@options[:archives].first}/#{archive_name}' #{@source}" ]
104
- end
116
+ [ "wget -cq -O '#{@options[:archives].first}/#{archive_name}' #{@source}" ]
105
117
  end
106
118
 
107
119
  def extract_commands #:nodoc:
@@ -20,6 +20,13 @@ module Sprinkle
20
20
  # end
21
21
 
22
22
  class Thor < Installer
23
+
24
+ api do
25
+ def thor(name, options = {}, &block)
26
+ install Sprinkle::Installers::Thor.new(self, name, options, &block)
27
+ end
28
+ end
29
+
23
30
  def initialize(parent, commands, options = {}, &block) #:nodoc:
24
31
  super parent, options, &block
25
32
  @commands = commands
@@ -84,16 +84,46 @@ module Sprinkle
84
84
  # directories or changing permissions), you can use the pre/post :install directives
85
85
  # and they will be run.
86
86
  class Transfer < Installer
87
- attr_accessor :source, :destination #:nodoc:
87
+ attr_accessor :source, :destination, :sourcepath #:nodoc:
88
+
89
+ api do
90
+ def transfer(source, destination, options = {}, &block)
91
+ options.merge!(:binding => binding())
92
+ install Sprinkle::Installers::Transfer.new(self, source, destination, options, &block)
93
+ end
94
+ end
88
95
 
89
96
  def initialize(parent, source, destination, options={}, &block) #:nodoc:
90
- super parent, options, &block
91
97
  @source = source
92
98
  @destination = destination
99
+ @orig_destination = destination
100
+ super parent, options, &block
101
+ @binding = options[:binding]
102
+ # perform the transfer in two steps if we're using sudo
103
+ if sudo?
104
+ final = @destination
105
+ @destination = "/tmp/sprinkle_#{File.basename(@destination)}"
106
+ post :install, "#{sudo_cmd}mv #{@destination} #{final}"
107
+ end
108
+ owner(options[:owner]) if options[:owner]
109
+ mode(options[:mode]) if options[:mode]
110
+
111
+ options[:render]=true if source_is_template?
112
+ options[:recursive]=false if options[:render]
113
+ end
114
+
115
+ def owner(owner)
116
+ @owner = owner
117
+ post :install, "#{sudo_cmd}chown #{owner} #{@orig_destination}"
118
+ end
119
+
120
+ def mode(mode)
121
+ @mode = mode
122
+ post :install, "#{sudo_cmd}chmod #{mode} #{@orig_destination}"
93
123
  end
94
124
 
95
125
  def install_commands
96
- nil
126
+ :TRANSFER
97
127
  end
98
128
 
99
129
  def self.render_template(template, context, prefix)
@@ -118,60 +148,51 @@ module Sprinkle
118
148
  end
119
149
 
120
150
  def render_template_file(path, context, prefix)
121
- template = File.read(path)
151
+ template = source_is_template? ? path : File.read(path)
122
152
  tempfile = render_template(template, context, @package.name)
123
153
  tempfile
124
154
  end
155
+
156
+ def source_is_template?
157
+ @source.split("\n").size>1
158
+ end
125
159
 
126
160
  def process(roles) #:nodoc:
127
161
  assert_delivery
128
162
 
129
- if logger.debug?
130
- logger.debug "transfer: #{@source} -> #{@destination} for roles: #{roles}\n"
131
- end
163
+ logger.debug "transfer: #{@source} -> #{@destination} for roles: #{roles}\n"
132
164
 
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, [pre].flatten, roles
139
- end
165
+ return if Sprinkle::OPTIONS[:testing]
140
166
 
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
167
+ if options[:render]
168
+ if options[:locals]
169
+ context = {}
170
+ options[:locals].each_pair do |k,v|
171
+ if v.respond_to?(:call)
172
+ context[k] = v.call
173
+ else
174
+ context[k] = v
152
175
  end
153
- else
154
- context = binding()
155
176
  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
177
  else
162
- sourcepath = @source
178
+ # context = binding()
179
+ context = @binding
163
180
  end
164
181
 
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, [post].flatten, roles
182
+ tempfile = render_template_file(@source, context, @package.name)
183
+ @sourcepath = tempfile.path
184
+ if source_is_template?
185
+ logger.debug "Rendering inline template to temporary file #{sourcepath}"
186
+ else
187
+ logger.debug "Rendering template #{@source} to temporary file #{sourcepath}"
173
188
  end
189
+ recursive = false
190
+ else
191
+ @sourcepath = @source
174
192
  end
193
+
194
+ logger.debug " --> Transferring #{sourcepath} to #{@orig_destination} for roles: #{roles}"
195
+ @delivery.install(self, roles, :recursive => @options[:recursive])
175
196
  end
176
197
  end
177
198
  end
@@ -1,13 +1,43 @@
1
1
  module Sprinkle
2
2
  module Installers
3
+ # The user installer helps add users. You may pass flags as an option.
4
+ #
5
+ # == Example Usage
6
+ #
7
+ # package :users do
8
+ # add_user 'admin', :flags => "--disabled-password"
9
+ #
10
+ # verify do
11
+ # has_user 'admin', :in_group = "root"
12
+ # end
13
+ # end
14
+
3
15
  class User < Installer
4
- def initialize(package, username, options, &block)
5
- super package, &block
16
+
17
+ api do
18
+ def add_user(username, options={}, &block)
19
+ install Sprinkle::Installers::User.new(self, username, options, &block)
20
+ end
21
+ end
22
+
23
+ verify_api do
24
+ def has_user(user, opts = {})
25
+ if opts[:in_group]
26
+ @commands << "id -nG #{user} | xargs -n1 echo | grep #{opts[:in_group]}"
27
+ else
28
+ @commands << "id #{user}"
29
+ end
30
+ end
31
+ end
32
+
33
+ def initialize(package, username, options = {}, &block) #:nodoc:
34
+ super package, options, &block
6
35
  @username = username
7
- @options = options
8
36
  end
37
+
9
38
  protected
10
- def install_commands
39
+
40
+ def install_commands #:nodoc:
11
41
  "adduser #{@options[:flags]} #{@username}"
12
42
  end
13
43
  end
@@ -1,7 +1,5 @@
1
1
  module Sprinkle
2
2
  module Installers
3
- # = Yum Package Installer
4
- #
5
3
  # The Yum package installer installs RPM packages.
6
4
  #
7
5
  # == Example Usage
@@ -10,20 +8,22 @@ module Sprinkle
10
8
  #
11
9
  # package :magic_beans do
12
10
  # yum 'magic_beans'
11
+ # verify { has_yum 'magic_beans' }
13
12
  # end
14
13
  #
15
- # You may also specify multiple rpms as an array:
14
+ # You may also specify multiple rpms as arguments or an array:
16
15
  #
17
16
  # package :magic_beans do
18
- # yum %w(magic_beans magic_sauce)
17
+ # yum "magic_beans", "magic_sauce"
19
18
  # end
20
- class Yum < Installer
21
- attr_accessor :packages #:nodoc:
19
+ class Yum < PackageInstaller
20
+
21
+ auto_api
22
22
 
23
- def initialize(parent, packages, &block) #:nodoc:
24
- super parent, &block
25
- packages = [packages] unless packages.is_a? Array
26
- @packages = packages
23
+ verify_api do
24
+ def has_yum(package)
25
+ @commands << "yum list installed #{package} | grep ^#{package}"
26
+ end
27
27
  end
28
28
 
29
29
  protected