jsierles-sprinkle 0.1.9

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 (89) hide show
  1. data/CREDITS +19 -0
  2. data/History.txt +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +87 -0
  5. data/README.txt +238 -0
  6. data/Rakefile +4 -0
  7. data/bin/sprinkle +86 -0
  8. data/config/hoe.rb +70 -0
  9. data/config/requirements.rb +17 -0
  10. data/examples/packages/build_essential.rb +9 -0
  11. data/examples/packages/databases/mysql.rb +13 -0
  12. data/examples/packages/databases/sqlite3.rb +16 -0
  13. data/examples/packages/phusion.rb +55 -0
  14. data/examples/packages/ruby/rails.rb +9 -0
  15. data/examples/packages/ruby/ruby.rb +17 -0
  16. data/examples/packages/ruby/rubygems.rb +17 -0
  17. data/examples/packages/scm/git.rb +11 -0
  18. data/examples/packages/scm/subversion.rb +4 -0
  19. data/examples/packages/servers/apache.rb +15 -0
  20. data/examples/rails/README +15 -0
  21. data/examples/rails/deploy.rb +2 -0
  22. data/examples/rails/packages/database.rb +9 -0
  23. data/examples/rails/packages/essential.rb +9 -0
  24. data/examples/rails/packages/rails.rb +28 -0
  25. data/examples/rails/packages/scm.rb +11 -0
  26. data/examples/rails/packages/search.rb +11 -0
  27. data/examples/rails/packages/server.rb +28 -0
  28. data/examples/rails/rails.rb +73 -0
  29. data/examples/sprinkle/sprinkle.rb +38 -0
  30. data/lib/sprinkle.rb +32 -0
  31. data/lib/sprinkle/actors/actors.rb +17 -0
  32. data/lib/sprinkle/actors/capistrano.rb +117 -0
  33. data/lib/sprinkle/actors/local.rb +26 -0
  34. data/lib/sprinkle/actors/ssh.rb +81 -0
  35. data/lib/sprinkle/actors/vlad.rb +65 -0
  36. data/lib/sprinkle/configurable.rb +31 -0
  37. data/lib/sprinkle/deployment.rb +73 -0
  38. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  39. data/lib/sprinkle/extensions/array.rb +5 -0
  40. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  41. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  42. data/lib/sprinkle/extensions/string.rb +10 -0
  43. data/lib/sprinkle/extensions/symbol.rb +7 -0
  44. data/lib/sprinkle/installers/apt.rb +52 -0
  45. data/lib/sprinkle/installers/deb.rb +38 -0
  46. data/lib/sprinkle/installers/gem.rb +62 -0
  47. data/lib/sprinkle/installers/installer.rb +120 -0
  48. data/lib/sprinkle/installers/rake.rb +37 -0
  49. data/lib/sprinkle/installers/rpm.rb +37 -0
  50. data/lib/sprinkle/installers/source.rb +179 -0
  51. data/lib/sprinkle/installers/yum.rb +37 -0
  52. data/lib/sprinkle/package.rb +233 -0
  53. data/lib/sprinkle/policy.rb +125 -0
  54. data/lib/sprinkle/script.rb +23 -0
  55. data/lib/sprinkle/verifiers/directory.rb +16 -0
  56. data/lib/sprinkle/verifiers/executable.rb +36 -0
  57. data/lib/sprinkle/verifiers/file.rb +20 -0
  58. data/lib/sprinkle/verifiers/process.rb +21 -0
  59. data/lib/sprinkle/verifiers/ruby.rb +25 -0
  60. data/lib/sprinkle/verifiers/symlink.rb +30 -0
  61. data/lib/sprinkle/verify.rb +114 -0
  62. data/lib/sprinkle/version.rb +9 -0
  63. data/script/destroy +14 -0
  64. data/script/generate +14 -0
  65. data/spec/spec.opts +1 -0
  66. data/spec/spec_helper.rb +17 -0
  67. data/spec/sprinkle/actors/capistrano_spec.rb +170 -0
  68. data/spec/sprinkle/actors/local_spec.rb +29 -0
  69. data/spec/sprinkle/configurable_spec.rb +46 -0
  70. data/spec/sprinkle/deployment_spec.rb +80 -0
  71. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  72. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  73. data/spec/sprinkle/installers/apt_spec.rb +70 -0
  74. data/spec/sprinkle/installers/gem_spec.rb +75 -0
  75. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  76. data/spec/sprinkle/installers/rake_spec.rb +29 -0
  77. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  78. data/spec/sprinkle/installers/source_spec.rb +331 -0
  79. data/spec/sprinkle/installers/yum_spec.rb +49 -0
  80. data/spec/sprinkle/package_spec.rb +422 -0
  81. data/spec/sprinkle/policy_spec.rb +126 -0
  82. data/spec/sprinkle/script_spec.rb +51 -0
  83. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  84. data/spec/sprinkle/verify_spec.rb +160 -0
  85. data/sprinkle.gemspec +70 -0
  86. data/tasks/deployment.rake +34 -0
  87. data/tasks/environment.rake +7 -0
  88. data/tasks/rspec.rake +21 -0
  89. metadata +180 -0
@@ -0,0 +1,422 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sprinkle::Package do
4
+ include Sprinkle::Package
5
+
6
+ before do
7
+ @name = :package_name
8
+ @empty = Proc.new { }
9
+ @opts = { }
10
+ end
11
+
12
+ # Kind of a messy way to do this but it works and DRYs out
13
+ # the specs. Checks to make sure an installer is receiving
14
+ # the block passed to it throught the package block.
15
+ def check_block_forwarding_on(installer)
16
+ eval(<<CODE)
17
+ pre_count = 0
18
+ lambda {
19
+ pkg = package @name do
20
+ #{installer} 'archive' do
21
+ pre :install, 'preOp'
22
+ end
23
+ end
24
+
25
+ pre_count = pkg.installer.instance_variable_get(:@pre)[:install].length
26
+ }.should change { pre_count }.by(1)
27
+ CODE
28
+ end
29
+
30
+ # More of Mitchell's meta-programming to dry up specs.
31
+ def create_package_with_blank_verify(n = 1)
32
+ eval(<<CODE)
33
+ @pkg = package @name do
34
+ gem 'gem'
35
+ #{"verify 'stuff happens' do; end\n" * n}
36
+ end
37
+ CODE
38
+ end
39
+
40
+ describe 'when created' do
41
+
42
+ it 'should be invalid without a block descriptor' do
43
+ lambda { package @name }.should raise_error
44
+ end
45
+
46
+ it 'should be invalid without a name' do
47
+ lambda { package nil, &@empty }.should raise_error
48
+ lambda { package @name, &@empty }.should_not raise_error
49
+ end
50
+
51
+ it 'should optionally accept a description' do
52
+ pkg = package @name do
53
+ description 'my package description'
54
+ end
55
+ pkg.description.should == 'my package description'
56
+ end
57
+
58
+ it 'should optionally accept a version' do
59
+ pkg = package @name do
60
+ version '2.0.2'
61
+ end
62
+ pkg.version.should == '2.0.2'
63
+ end
64
+
65
+ it 'should optionally accept an installer' do
66
+ pkg = package @name do
67
+ gem 'rails'
68
+ end
69
+ pkg.installer.should_not be_nil
70
+ end
71
+
72
+ it 'should optionally accept dependencies' do
73
+ pkg = package @name do
74
+ requires :webserver, :database
75
+ end
76
+ pkg.dependencies.should == [:webserver, :database]
77
+ end
78
+
79
+ it 'should optionally accept recommended dependencies' do
80
+ pkg = package @name do
81
+ recommends :webserver, :database
82
+ end
83
+ pkg.recommends.should == [:webserver, :database]
84
+ end
85
+
86
+ it 'should optionally define a virtual package implementation' do
87
+ pkg = package @name, :provides => :database do; end
88
+ pkg.provides.should == :database
89
+ end
90
+
91
+ it 'should be able to represent itself as a string' do
92
+ pkg = package @name do; end
93
+ pkg.to_s.should == @name
94
+ end
95
+
96
+ end
97
+
98
+ describe 'helper method' do
99
+
100
+ it 'should added new packages to the global package hash' do
101
+ pkg = package @name do; end
102
+ Sprinkle::Package::PACKAGES[@name].should == pkg
103
+ end
104
+
105
+ it 'should add the new package to the provides list if specified' do
106
+ pkg = package @name, :provides => :database do; end
107
+ Sprinkle::Package::PACKAGES[:database].last.should == pkg
108
+ end
109
+
110
+ end
111
+
112
+ describe 'installer configuration' do
113
+
114
+ it 'should optionally accept an apt installer' do
115
+ pkg = package @name do
116
+ apt %w( deb1 deb2 )
117
+ end
118
+ pkg.should respond_to(:apt)
119
+ pkg.installer.class.should == Sprinkle::Installers::Apt
120
+ end
121
+
122
+ it 'should optionally accept an rpm installer' do
123
+ pkg = package @name do
124
+ rpm %w( rpm1 rpm2 )
125
+ end
126
+ pkg.should respond_to(:rpm)
127
+ pkg.installer.class.should == Sprinkle::Installers::Rpm
128
+ end
129
+
130
+ it 'should optionally accept a gem installer' do
131
+ pkg = package @name do
132
+ gem 'gem'
133
+ end
134
+ pkg.should respond_to(:gem)
135
+ pkg.installer.class.should == Sprinkle::Installers::Gem
136
+ end
137
+
138
+ it 'should optionally accept a source installer' do
139
+ pkg = package @name do
140
+ source 'archive'
141
+ end
142
+ pkg.should respond_to(:source)
143
+ pkg.installer.class.should == Sprinkle::Installers::Source
144
+ end
145
+
146
+ end
147
+
148
+ describe 'with a source installer' do
149
+
150
+ it 'should optionally accept a block containing customisations' do
151
+ pkg = package @name do
152
+ source 'archive' do; end
153
+ end
154
+ pkg.should respond_to(:source)
155
+ pkg.installer.class.should == Sprinkle::Installers::Source
156
+ end
157
+
158
+ it 'should forward block to installer superclass' do
159
+ check_block_forwarding_on(:source)
160
+ end
161
+
162
+ it 'should automatically add a build essential recommendation' do
163
+ pkg = package @name do
164
+ source 'archive'
165
+ end
166
+ pkg.recommends.should include(:build_essential)
167
+ end
168
+
169
+ end
170
+
171
+ describe 'with an apt installer' do
172
+ it 'should forward block to installer superclass' do
173
+ check_block_forwarding_on(:apt)
174
+ end
175
+ end
176
+
177
+ describe 'with an rpm installer' do
178
+ it 'should forward block to installer superclass' do
179
+ check_block_forwarding_on(:rpm)
180
+ end
181
+ end
182
+
183
+ describe 'with an gem installer' do
184
+
185
+ it 'should automatically add a rubygems recommendation' do
186
+ pkg = package @name do
187
+ gem 'gem'
188
+ end
189
+ pkg.recommends.should include(:rubygems)
190
+ end
191
+
192
+ it 'should forward block to installer superclass' do
193
+ check_block_forwarding_on(:gem)
194
+ end
195
+
196
+ end
197
+
198
+ describe 'when processing' do
199
+
200
+ before do
201
+ @deployment = mock(Sprinkle::Deployment)
202
+ @roles = [ :app, :db ]
203
+ @installer = mock(Sprinkle::Installers::Installer, :defaults => true, :process => true)
204
+ @package = package @name do; end
205
+ end
206
+
207
+ describe 'with an installer' do
208
+
209
+ before do
210
+ @package.installer = @installer
211
+ end
212
+
213
+ it 'should configure itself against the deployment context' do
214
+ @installer.should_receive(:defaults).with(@deployment).and_return
215
+ end
216
+
217
+ it 'should request the installer to process itself' do
218
+ @installer.should_receive(:process).with(@roles).and_return
219
+ end
220
+
221
+ after do
222
+ @package.process(@deployment, @roles)
223
+ end
224
+ end
225
+
226
+ describe 'without an installer' do
227
+
228
+ it 'should not request the installer to process if the package is a metapackage' do
229
+ @installer.should_not_receive(:process)
230
+ @package.process(@deployment, @roles)
231
+ end
232
+
233
+ end
234
+
235
+ describe 'with verifications' do
236
+ before do
237
+ @pkg = create_package_with_blank_verify(3)
238
+ @pkg.installer = @installer
239
+ @installer.stub!(:defaults)
240
+ @installer.stub!(:process)
241
+ end
242
+
243
+ describe 'with forcing' do
244
+ before do
245
+ # Being explicit
246
+ Sprinkle::OPTIONS[:force] = true
247
+ end
248
+
249
+ it 'should process verifications only once' do
250
+ @pkg.should_receive(:process_verifications).once
251
+ @pkg.process(@deployment, @roles)
252
+ end
253
+
254
+ after do
255
+ # Being explicit
256
+ Sprinkle::OPTIONS[:force] = false
257
+ end
258
+ end
259
+
260
+ describe 'without forcing' do
261
+ before do
262
+ # Being explicit
263
+ Sprinkle::OPTIONS[:force] = false
264
+ end
265
+
266
+ it 'should process verifications twice' do
267
+ @pkg.should_receive(:process_verifications).once.with(@deployment, @roles, true).and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
268
+ @pkg.should_receive(:process_verifications).once.with(@deployment, @roles).and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
269
+ end
270
+
271
+ it 'should continue with installation if pre-verification fails' do
272
+ @pkg.should_receive(:process_verifications).twice.and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
273
+ @installer.should_receive(:defaults)
274
+ @installer.should_receive(:process)
275
+ end
276
+
277
+ it 'should only process verifications once and should not process installer if verifications succeed' do
278
+ @pkg.should_receive(:process_verifications).once.and_return(nil)
279
+ @installer.should_not_receive(:defaults)
280
+ @installer.should_not_receive(:process)
281
+ end
282
+
283
+ after do
284
+ begin
285
+ @pkg.process(@deployment, @roles)
286
+ rescue Sprinkle::VerificationFailed => e; end
287
+ end
288
+ end
289
+ end
290
+
291
+ end
292
+
293
+ describe 'when processing verifications' do
294
+ before do
295
+ @deployment = mock(Sprinkle::Deployment)
296
+ @roles = [ :app, :db ]
297
+ @installer = mock(Sprinkle::Installers::Installer, :defaults => true, :process => true)
298
+ @pkg = create_package_with_blank_verify(3)
299
+ @pkg.installer = @installer
300
+ @installer.stub!(:defaults)
301
+ @installer.stub!(:process)
302
+ @logger = mock(ActiveSupport::BufferedLogger, :debug => true, :debug? => true)
303
+ @logger.stub!(:info)
304
+ end
305
+
306
+ it 'should request _each_ verification to configure itself against the deployment context' do
307
+ @pkg.verifications.each do |v|
308
+ v.should_receive(:defaults).with(@deployment).once
309
+ v.stub!(:process)
310
+ end
311
+ end
312
+
313
+ it 'should request _each_ verification to process' do
314
+ @pkg.verifications.each do |v|
315
+ v.stub!(:defaults)
316
+ v.should_receive(:process).with(@roles).once
317
+ end
318
+ end
319
+
320
+ it 'should enter a log info event to notify user whats happening' do
321
+ @pkg.verifications.each do |v|
322
+ v.stub!(:defaults)
323
+ v.stub!(:process)
324
+ end
325
+
326
+ @pkg.should_receive(:logger).once.and_return(@logger)
327
+ end
328
+
329
+ after do
330
+ @pkg.process_verifications(@deployment, @roles)
331
+ end
332
+ end
333
+
334
+ describe 'hierarchies' do
335
+
336
+ before do
337
+ @a = package :a do; requires :b; end
338
+ @b = package :b do; requires :c; end
339
+ @c = package :c do; recommends :d; end
340
+ @d = package :d do; end
341
+ end
342
+
343
+ it 'should be able to return a dependency hierarchy tree' do
344
+ @a.tree.flatten.should == [ @d, @c, @b, @a ]
345
+ @b.tree.flatten.should == [ @d, @c, @b ]
346
+ @c.tree.flatten.should == [ @d, @c ]
347
+ @d.tree.flatten.should == [ @d ]
348
+ end
349
+
350
+ describe 'with missing recommendations' do
351
+
352
+ before do
353
+ @d.recommends :e
354
+ end
355
+
356
+ it 'should ignore missing recommendations' do
357
+ @d.tree.flatten.should == [ @d ]
358
+ end
359
+
360
+ end
361
+
362
+ it 'should optionally accept a block to call upon item in the tree during hierarchy traversal' do
363
+ @count = 0
364
+ @a.tree do
365
+ @count += 1
366
+ end
367
+ @count.should == 3
368
+ end
369
+
370
+ it 'should maintain a depth count of how deep the hierarchy is' do
371
+ @b.should_receive(:tree).with(2).and_return([@b])
372
+ @a.tree do; end
373
+ end
374
+
375
+ end
376
+
377
+ describe 'with missing dependencies' do
378
+
379
+ before do
380
+ @pkg = package @name do
381
+ gem 'gem'
382
+ requires :missing
383
+ end
384
+ end
385
+
386
+ it 'should raise an error if a package is missing' do
387
+ lambda { @pkg.tree }.should raise_error
388
+ end
389
+
390
+ end
391
+
392
+ describe 'with verifications' do
393
+ it 'should create a Sprinkle::Verification object for the verify block' do
394
+ Sprinkle::Verify.should_receive(:new).once
395
+
396
+ create_package_with_blank_verify
397
+ end
398
+
399
+ it 'should create multiple Sprinkle::Verification objects for multiple verify blocks' do
400
+ Sprinkle::Verify.should_receive(:new).twice
401
+
402
+ create_package_with_blank_verify(2)
403
+ end
404
+
405
+ it 'should add each Sprinkle::Verificaton object to the @verifications array' do
406
+ @pkg = create_package_with_blank_verify(3)
407
+ @pkg.verifications.length.should eql(3)
408
+ end
409
+
410
+ it 'should initialize Sprinkle::Verification with the package name, description, and block' do
411
+ Sprinkle::Verify.should_receive(:new) do |pkg, desc|
412
+ pkg.name.should eql(@name)
413
+ desc.should eql('stuff happens')
414
+ end
415
+
416
+ # We do a should_not raise_error because if a block was NOT passed, an error
417
+ # is raised. This is specced in verification_spec.rb
418
+ lambda { create_package_with_blank_verify }.should_not raise_error
419
+ end
420
+ end
421
+
422
+ end
@@ -0,0 +1,126 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sprinkle::Policy do
4
+ include Sprinkle::Policy
5
+
6
+ before do
7
+ @name = 'a policy'
8
+ end
9
+
10
+ describe 'when created' do
11
+
12
+ it 'should be invalid without a name' do
13
+ lambda { policy nil }.should raise_error
14
+ end
15
+
16
+ it 'should be invalid without role definitions' do
17
+ lambda { policy @name do; end }.should raise_error
18
+ lambda { policy @name, :roles => :app do; end }.should_not raise_error
19
+ end
20
+
21
+ it 'should optionally accept package dependencies' do
22
+ p = policy @name, :roles => :app do; end
23
+ p.should respond_to(:requires)
24
+ p.requires :appserver
25
+ p.packages.should == [ :appserver ]
26
+ end
27
+
28
+ it 'should optionally accept package dependencies with versions' do
29
+ p = policy @name, :roles => :app do; end
30
+ p.requires :appserver, :version => 2
31
+ p.packages.should == [ :appserver ]
32
+ pending 'requires version checking implementation'
33
+ end
34
+
35
+ it 'should add itself to the global policy list' do
36
+ sz = Sprinkle::Policy::POLICIES.size
37
+ p = policy @name, :roles => :app do; end
38
+ Sprinkle::Policy::POLICIES.size.should == sz + 1
39
+ Sprinkle::Policy::POLICIES.last.should == p
40
+ end
41
+
42
+ end
43
+
44
+ describe 'with packages' do
45
+ include Sprinkle::Package
46
+
47
+ before do
48
+ @deployment = mock(Sprinkle::Deployment)
49
+ Sprinkle::Package::PACKAGES.clear # reset full package list before each spec is run
50
+
51
+ @a = package :a do; requires :b; requires :c; end
52
+ @b = package :b, :provides => :xyz do; end
53
+ @c = package :c, :provides => :abc do; end
54
+ @d = package :d, :provides => :abc do; end
55
+
56
+ @policy = policy :test, :roles => :app do; requires :a; end
57
+ $terminal.stub!(:choose).and_return(:c) # stub out highline asking questions
58
+ end
59
+
60
+ describe 'when applying' do
61
+ include Sprinkle::Package
62
+
63
+ it 'should determine the packages to install via the hierarchy dependency tree of each package in the policy' do
64
+ @a.should_receive(:process).and_return
65
+ @b.should_receive(:process).and_return
66
+ @c.should_receive(:process).and_return
67
+ @d.should_not_receive(:process)
68
+ end
69
+
70
+ it 'should normalize (ie remove duplicates from) the installation order of all packages including dependencies' do
71
+ @e = package :e do; requires :b; end
72
+ @policy.requires :e
73
+
74
+ @a.should_receive(:process).once.and_return
75
+ @b.should_receive(:process).once.and_return
76
+ @c.should_receive(:process).once.and_return
77
+ @d.should_not_receive(:process)
78
+ @e.should_receive(:process).once.and_return
79
+ end
80
+ end
81
+
82
+ describe 'containing package dependencies with versions' do
83
+
84
+ it 'should be invalid if the specified package does not exist'
85
+ it 'should ignore any packages of the same name that have other versions'
86
+ it 'should select the correct package version when applying'
87
+
88
+ end
89
+
90
+ describe 'containing virtual packages' do
91
+
92
+ it 'should automatically select a concrete package implementation for a virtual one when there exists only one possible selection' do
93
+ @policy = policy :virtual, :roles => :app do; requires :xyz; end
94
+ Sprinkle::Package::PACKAGES[:xyz].should == [ @b ]
95
+ end
96
+
97
+ it 'should ask the user for the concrete package implementation to use for a virtual one when more than one possible choice exists' do
98
+ @policy = policy :virtual, :roles => :app do; requires :abc; end
99
+ Sprinkle::Package::PACKAGES[:abc].should include(@c)
100
+ Sprinkle::Package::PACKAGES[:abc].should include(@d)
101
+ $terminal.should_receive(:choose).and_return(:c)
102
+ end
103
+
104
+ end
105
+
106
+ after do
107
+ @policy.process(@deployment)
108
+ end
109
+ end
110
+ end
111
+
112
+ describe Sprinkle::Policy, 'with missing packages' do
113
+
114
+ before do
115
+ @deployment = mock(Sprinkle::Deployment)
116
+ Sprinkle::Package::PACKAGES.clear # reset full package list before each spec is run
117
+
118
+ @policy = policy :test, :roles => :app do; requires :z; end
119
+ $terminal.stub!(:choose).and_return(:c) # stub out highline asking questions
120
+ end
121
+
122
+ it 'should raise an error if a package is missing' do
123
+ lambda { @policy.process(@deployment) }.should raise_error
124
+ end
125
+
126
+ end