sprinkle 0.5.2 → 0.6.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ * push_text was escaping & and / when it should not be
2
+
3
+ *Stefano Diem Benatti*
4
+
1
5
  * Sprinkle `sudo_cmd` and Capistrino should work together instead of getting in each others way
2
6
 
3
7
  When using the capistrano actor `sudo_cmd` will now use the capistrano
@@ -13,3 +17,19 @@
13
17
  * verify of local actor was never returning false so installers would never be executed
14
18
 
15
19
  *Edgars Beigarts*
20
+
21
+ * Capistrano actor now defaults to loading "Capfile" not "deploy" when no block is given.
22
+ If for some reason you just have a 'deploy' file in your root folder you
23
+ should `capify .` your setup and move your deploy.rb file into the config
24
+ folder. Or you can provide a block with `recipe 'deploy'` to force the
25
+ old behavior.
26
+
27
+ *Josh Goebel*
28
+
29
+ * Capistrano actor now uses the configured setting of `run_method`, instead of always sudo.
30
+ The default Capistrano setup prefers sudo, so nothing should change for
31
+ most users. If you want to NOT use sudo to run commands you can set
32
+ `use_sudo` or `run_method` accordingly in your capistrano recipes:
33
+ `set :use_sudo, false` or `set :run_method, :run`
34
+
35
+ *Michael Nigh*
@@ -30,16 +30,16 @@ module Sprinkle
30
30
  def @config.recipes(script)
31
31
  _sprinkle_actor.recipes(script)
32
32
  end
33
-
33
+
34
34
  if block
35
35
  @config.instance_eval &block
36
36
  else
37
- @config.load 'deploy' # normally in the config directory for rails
37
+ @config.load "Capfile" if File.exist?("Capfile")
38
38
  end
39
39
  end
40
40
 
41
41
  def sudo?
42
- @config.fetch(:run_method, :sudo) == :sudo
42
+ @config.fetch(:run_method, :run) == :sudo
43
43
  end
44
44
 
45
45
  def sudo_command
@@ -49,7 +49,7 @@ module Sprinkle
49
49
  # Determines if there are any servers for the given roles
50
50
  def servers_for_role?(roles)
51
51
  roles=Array(roles)
52
- roles.any? { |r| @config.roles.keys.include? (r) }
52
+ roles.any? { |r| @config.roles.keys.include?(r) }
53
53
  end
54
54
 
55
55
 
@@ -97,7 +97,7 @@ module Sprinkle
97
97
  @log_recorder = log_recorder = Sprinkle::Utility::LogRecorder.new
98
98
  commands = commands.map {|x| rewrite_command(x)}
99
99
  define_task(name, roles) do
100
- via = fetch(:run_method, :sudo)
100
+ via = fetch(:run_method, :run)
101
101
  commands.each do |command|
102
102
  if command == :TRANSFER
103
103
  opts.reverse_merge!(:recursive => true)
@@ -108,9 +108,9 @@ module Sprinkle
108
108
  else
109
109
  # this reset the log
110
110
  log_recorder.reset command
111
- invoke_command(command, {:via => via}) do |c,s,d|
112
- # record the stream and data
113
- log_recorder.log(s, d)
111
+ invoke_command(command, {:via => via}) do |ch, stream, out|
112
+ ::Capistrano::Configuration.default_io_proc.call(ch, stream, out) if Sprinkle::OPTIONS[:verbose]
113
+ log_recorder.log(stream, out)
114
114
  end
115
115
  end
116
116
  end
@@ -123,7 +123,7 @@ module Sprinkle
123
123
  # rip out any double sudos from the beginning of the command
124
124
  def rewrite_command(cmd)
125
125
  return cmd if cmd.is_a?(Symbol)
126
- via = @config.fetch(:run_method, :sudo)
126
+ via = @config.fetch(:run_method, :run)
127
127
  if via == :sudo and cmd =~ /^#{sudo_command}/
128
128
  cmd.gsub(/^#{sudo_command}\s?/,"")
129
129
  else
@@ -19,7 +19,7 @@ module Sprinkle
19
19
  # Determines if there are any servers for the given roles
20
20
  def servers_for_role?(roles)
21
21
  roles=Array(roles)
22
- roles.any? { |r| @roles.keys.include? (r) }
22
+ roles.any? { |r| @roles.keys.include?(r) }
23
23
  end
24
24
 
25
25
  def install(installer, roles, opts={})
@@ -43,7 +43,7 @@ module Sprinkle
43
43
 
44
44
  def initialize(options = {}, &block) #:nodoc:
45
45
  @options = options.update(:user => 'root')
46
- @roles = {}.with_indifferent_access
46
+ @roles = {}
47
47
  @connection_cache = SSHConnectionCache.new
48
48
  self.instance_eval &block if block
49
49
  raise "You must define at least a single role." if @roles.empty?
@@ -0,0 +1,56 @@
1
+ module Sprinkle
2
+ module Attributes
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attr_accessor :delivery
7
+ end
8
+
9
+ def defaults(deployment)
10
+ defaults = deployment.defaults[self.class.name.split(/::/).last.downcase.to_sym]
11
+ self.set_defaults(&defaults) if defaults
12
+ @delivery = deployment.style
13
+ end
14
+
15
+ def set_defaults(&block)
16
+ before = @options
17
+ @options = {}
18
+ self.instance_eval(&block) if block
19
+ @options = before.reverse_merge(@options)
20
+ end
21
+
22
+ private
23
+
24
+ def read_from_package(m)
25
+ @package.send(m) if @package.respond_to?(m)
26
+ end
27
+
28
+ def option?(sym)
29
+ !!@options[sym]
30
+ end
31
+
32
+ module ClassMethods
33
+
34
+ def attributes(*list)
35
+ list.each do |a|
36
+ define_method a do |*val|
37
+ val=nil if val.empty?
38
+ val ? @options[a] = val.first : @options[a] || read_from_package(a)
39
+ end
40
+ end
41
+ end
42
+
43
+ def multi_attributes(*list)
44
+ list.each do |a|
45
+ define_method a do |*val|
46
+ val = val.try(:first)
47
+ return @options[a] unless val
48
+ @options[a]||=[]
49
+ val.is_a?(Array) ? @options[a] += val : @options[a] << val
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -31,6 +31,8 @@ module Sprinkle
31
31
  super parent, *packages, &block
32
32
  @options.reverse_merge!(:dependencies_only => false)
33
33
  end
34
+
35
+ attributes :dependencies_only
34
36
 
35
37
  auto_api
36
38
 
@@ -44,8 +46,8 @@ module Sprinkle
44
46
 
45
47
  def install_commands #:nodoc:
46
48
  command = @options[:dependencies_only] ? 'build-dep' : 'install'
47
- noninteractive = "env DEBCONF_TERSE='yes' DEBIAN_PRIORITY='critical' DEBIAN_FRONTEND=noninteractive"
48
- "#{noninteractive} #{sudo_cmd}apt-get --force-yes -qyu #{command} #{@packages.join(' ')}"
49
+ noninteractive = "#{sudo_cmd}env DEBCONF_TERSE='yes' DEBIAN_PRIORITY='critical' DEBIAN_FRONTEND=noninteractive"
50
+ "#{noninteractive} apt-get --force-yes -qyu #{command} #{@packages.join(' ')}"
49
51
  end
50
52
 
51
53
  end
@@ -29,13 +29,13 @@ module Sprinkle
29
29
  raise 'No installation area defined' unless @options[:prefix]
30
30
  raise 'No archive download area defined' unless @options[:archives]
31
31
 
32
- [ "mkdir -p #{@options[:prefix].first}",
33
- "mkdir -p #{@options[:archives].first}" ]
32
+ [ "mkdir -p #{@options[:prefix]}",
33
+ "mkdir -p #{@options[:archives]}" ]
34
34
  end
35
35
 
36
36
  def install_commands #:nodoc:
37
- commands = [ "bash -c 'wget -cq --directory-prefix=#{@options[:archives].first} #{@binary_archive}'" ]
38
- commands << "bash -c \"cd #{@options[:prefix].first} && #{extract_command} '#{@options[:archives].first}/#{archive_name}'\""
37
+ commands = [ "bash -c 'wget -cq --directory-prefix=#{@options[:archives]} #{@binary_archive}'" ]
38
+ commands << "bash -c \"cd #{@options[:prefix]} && #{extract_command} '#{@options[:archives]}/#{archive_name}'\""
39
39
  end
40
40
 
41
41
  def archive_name #:nodoc:
@@ -41,14 +41,8 @@ module Sprinkle
41
41
  super parent, options, &block
42
42
  @gem = gem
43
43
  end
44
-
45
- def source(location = nil) #:nodoc:
46
- # package defines an installer called source so here we specify a method directly
47
- # rather than rely on the automatic options processing since packages' method missing
48
- # won't be run
49
- return @options[:source] unless location
50
- @options[:source] = location
51
- end
44
+
45
+ attributes :source, :repository, :http_proxy, :build_flags, :version
52
46
 
53
47
  protected
54
48
 
@@ -51,7 +51,8 @@ module Sprinkle
51
51
  # or post :install. If this is the case, it will be documented on
52
52
  # the installation method's corresponding documentation page.
53
53
  class Installer
54
- include Sprinkle::Configurable
54
+ include Sprinkle::Attributes
55
+
55
56
  attr_accessor :delivery, :package, :options, :pre, :post #:nodoc:
56
57
 
57
58
  def initialize(package, options = {}, &block) #:nodoc:
@@ -60,6 +61,8 @@ module Sprinkle
60
61
  @pre = {}; @post = {}
61
62
  self.instance_eval(&block) if block
62
63
  end
64
+
65
+ attributes :prefix, :archives, :builds
63
66
 
64
67
  class << self
65
68
  def subclasses
@@ -67,7 +70,7 @@ module Sprinkle
67
70
  end
68
71
 
69
72
  def api(&block)
70
- Sprinkle::Package::Package.class_eval &block
73
+ Sprinkle::Package::Package.add_api &block
71
74
  end
72
75
 
73
76
  def verify_api(&block)
@@ -88,19 +91,36 @@ module Sprinkle
88
91
  end
89
92
 
90
93
  def escape_shell_arg(str)
91
- str.gsub("'", "'\\\\''").gsub("/", "\\\\/").gsub("\n", '\n').gsub('&', '\\\&')
94
+ str.gsub("'", "'\\\\''").gsub("\n", '\n')
92
95
  end
93
96
 
94
- def pre(stage, *commands)
97
+ def pre(stage, *commands, &block)
95
98
  @pre[stage] ||= []
96
99
  @pre[stage] += commands
97
- @pre[stage] += [yield] if block_given?
100
+ @pre[stage] += commands_from_block(block)
98
101
  end
99
102
 
100
- def post(stage, *commands)
103
+ def post(stage, *commands, &block)
101
104
  @post[stage] ||= []
102
105
  @post[stage] += commands
103
- @post[stage] += [yield] if block_given?
106
+ @post[stage] += commands_from_block(block)
107
+ end
108
+
109
+ def commands_from_block(block)
110
+ return [] unless block
111
+ out = nil
112
+ diff = @package.with_private_install_queue do
113
+ out = block.call
114
+ end
115
+ diff.empty? ? out : diff.map {|x| x.install_sequence }
116
+ end
117
+
118
+ def method_missing(method, *args, &block)
119
+ if package.class.installer_methods.include?(method)
120
+ @package.send(method, *args, &block)
121
+ else
122
+ super(method, *args, &block)
123
+ end
104
124
  end
105
125
 
106
126
  def per_host?
@@ -113,8 +133,6 @@ module Sprinkle
113
133
  def announce; end
114
134
 
115
135
  def process(roles) #:nodoc:
116
- assert_delivery
117
-
118
136
  if logger.debug?
119
137
  sequence = install_sequence; sequence = sequence.join('; ') if sequence.is_a? Array
120
138
  logger.debug "#{@package.name} install sequence: #{sequence} for roles: #{roles}\n"
@@ -45,8 +45,12 @@ module Sprinkle
45
45
 
46
46
  protected
47
47
 
48
+ def escape_sed_arg(s)
49
+ escape_shell_arg(s).gsub("/", "\\\\/").gsub('&', '\\\&')
50
+ end
51
+
48
52
  def install_commands #:nodoc:
49
- "#{sudo_cmd}sed -i 's/#{escape_shell_arg(@regex)}/#{escape_shell_arg(@text)}/g' #{@path}"
53
+ "#{sudo_cmd}sed -i 's/#{escape_sed_arg(@regex)}/#{escape_sed_arg(@text)}/g' #{@path}"
50
54
  end
51
55
 
52
56
  end
@@ -22,6 +22,10 @@ module Sprinkle
22
22
  options = cmds.extract_options!
23
23
  install Runner.new(self, cmds, options, &block)
24
24
  end
25
+
26
+ def noop(&block)
27
+ install Runner.new(self, "echo noop", &block)
28
+ end
25
29
  end
26
30
 
27
31
  attr_accessor :cmds #:nodoc:
@@ -90,6 +90,9 @@ module Sprinkle
90
90
  @source = source
91
91
  end
92
92
 
93
+ multi_attributes :enable, :disable, :with, :without, :option,
94
+ :custom_install
95
+
93
96
  def install_sequence #:nodoc:
94
97
  prepare + download + extract + configure + build + install
95
98
  end
@@ -107,23 +110,23 @@ module Sprinkle
107
110
  raise 'No build area defined' unless @options[:builds]
108
111
  raise 'No source download area defined' unless @options[:archives]
109
112
 
110
- [ "mkdir -p #{@options[:prefix].first}",
111
- "mkdir -p #{@options[:builds].first}",
112
- "mkdir -p #{@options[:archives].first}" ]
113
+ [ "mkdir -p #{@options[:prefix]}",
114
+ "mkdir -p #{@options[:builds]}",
115
+ "mkdir -p #{@options[:archives]}" ]
113
116
  end
114
117
 
115
118
  def download_commands #:nodoc:
116
- [ "wget -cq -O '#{@options[:archives].first}/#{archive_name}' #{@source}" ]
119
+ [ "wget -cq -O '#{@options[:archives]}/#{archive_name}' #{@source}" ]
117
120
  end
118
121
 
119
122
  def extract_commands #:nodoc:
120
- [ "bash -c 'cd #{@options[:builds].first} && #{extract_command} #{@options[:archives].first}/#{archive_name}'" ]
123
+ [ "bash -c 'cd #{@options[:builds]} && #{extract_command} #{@options[:archives]}/#{archive_name}'" ]
121
124
  end
122
125
 
123
126
  def configure_commands #:nodoc:
124
127
  return [] if custom_install?
125
128
 
126
- command = "bash -c 'cd #{build_dir} && ./configure --prefix=#{@options[:prefix].first} "
129
+ command = "bash -c 'cd #{build_dir} && ./configure --prefix=#{@options[:prefix]} "
127
130
 
128
131
  extras = {
129
132
  :enable => '--enable', :disable => '--disable',
@@ -152,21 +155,33 @@ module Sprinkle
152
155
 
153
156
  # REVISIT: must be better processing of custom install commands somehow? use splat operator?
154
157
  def custom_install_commands #:nodoc:
155
- dress @options[:custom_install], :install
158
+ dress @options[:custom_install], nil, :install
156
159
  end
157
160
 
158
161
  protected
162
+
163
+ def pre_commands(stage) #:nodoc:
164
+ dress @pre[stage] || [], :pre, stage
165
+ end
166
+
167
+ def post_commands(stage) #:nodoc:
168
+ dress @post[stage] || [], :post, stage
169
+ end
170
+
159
171
 
160
172
  # dress is overriden from the base Sprinkle::Installers::Installer class so that the command changes
161
173
  # directory to the build directory first. Also, the result of the command is logged.
162
- def dress(commands, stage)
163
- commands.collect { |command| "bash -c 'cd #{build_dir} && #{command} >> #{@package.name}-#{stage}.log 2>&1'" }
174
+ def dress(commands, pre_or_post, stage)
175
+ chdir = "cd #{build_dir} && "
176
+ chdir = "" if [:prepare, :download].include?(stage)
177
+ chdir = "" if stage == :extract and pre_or_post == :pre
178
+ commands.collect { |command| "bash -c '#{chdir}#{command} >> #{@package.name}-#{stage}.log 2>&1'" }
164
179
  end
165
180
 
166
181
  private
167
182
 
168
183
  def create_options(key, prefix) #:nodoc:
169
- @options[key].first.inject('') { |m, option| m << "#{prefix}-#{option} "; m }
184
+ @options[key].inject('') { |m, option| m << "#{prefix}-#{option} "; m }
170
185
  end
171
186
 
172
187
  def extract_command #:nodoc:
@@ -195,7 +210,7 @@ module Sprinkle
195
210
  end
196
211
 
197
212
  def build_dir #:nodoc:
198
- "#{@options[:builds].first}/#{options[:custom_dir] || base_dir}"
213
+ "#{@options[:builds]}/#{options[:custom_dir] || base_dir}"
199
214
  end
200
215
 
201
216
  def base_dir #:nodoc:
@@ -158,8 +158,6 @@ module Sprinkle
158
158
  end
159
159
 
160
160
  def process(roles) #:nodoc:
161
- assert_delivery
162
-
163
161
  logger.debug "transfer: #{@source} -> #{@destination} for roles: #{roles}\n"
164
162
 
165
163
  return if Sprinkle::OPTIONS[:testing]
@@ -29,16 +29,19 @@ module Sprinkle
29
29
  end
30
30
  end
31
31
  end
32
-
32
+
33
33
  def initialize(package, username, options = {}, &block) #:nodoc:
34
34
  super package, options, &block
35
35
  @username = username
36
36
  end
37
-
37
+
38
38
  protected
39
39
 
40
40
  def install_commands #:nodoc:
41
- "adduser #{@options[:flags]} #{@username}"
41
+ noninteractive = "--gecos ,,,"
42
+ flags = @options[:flags] || ""
43
+ flags << noninteractive unless flags =~ /--gecos/
44
+ "adduser #{flags} #{@username}"
42
45
  end
43
46
  end
44
47
  end
@@ -106,9 +106,17 @@ module Sprinkle
106
106
  end
107
107
 
108
108
  class Package #:nodoc:
109
- # include ArbitraryOptions
110
109
  attr_accessor :name, :provides, :installers, :verifications
111
110
  attr_accessor :args, :opts
111
+ cattr_reader :installer_methods
112
+ @@installer_methods = []
113
+
114
+ def self.add_api(&block)
115
+ before = self.instance_methods
116
+ self.class_eval &block
117
+ added = self.instance_methods - before
118
+ @@installer_methods += added.map(&:to_sym)
119
+ end
112
120
 
113
121
  def initialize(name, metadata = {}, &block)
114
122
  raise 'No package name supplied' unless name
@@ -166,10 +174,6 @@ module Sprinkle
166
174
  raise ContextError, "Cannot call get inside a package, must be inside an Installer block"
167
175
  end
168
176
 
169
- def noop(&block)
170
- install Sprinkle::Installers::Runner.new(self, "echo noop", &block)
171
- end
172
-
173
177
  # meta installer
174
178
  # TODO - fix to be atomic
175
179
  def push_file(file, options ={}, &block)
@@ -249,6 +253,19 @@ module Sprinkle
249
253
  end
250
254
 
251
255
  def to_s; @name; end
256
+
257
+ # allow an installer to request a private install queue from the package
258
+ # for example to allow pre and post hooks to have their own installers that
259
+ # do not mess with the packages installer list
260
+ #
261
+ # returns: the private queue
262
+ def with_private_install_queue()
263
+ b = @installers
264
+ @installers = private_queue =[]
265
+ yield
266
+ @installers = b
267
+ private_queue
268
+ end
252
269
 
253
270
  protected
254
271
 
@@ -256,7 +273,7 @@ module Sprinkle
256
273
  @installers << i
257
274
  i
258
275
  end
259
-
276
+
260
277
  private
261
278
 
262
279
  def add_dependencies(packages, kind)
@@ -59,7 +59,7 @@ module Sprinkle
59
59
  # verify { has_magic_beans('ranch') }
60
60
  # end
61
61
  class Verify
62
- include Sprinkle::Configurable
62
+ include Sprinkle::Attributes
63
63
  attr_accessor :package, :description, :commands #:nodoc:
64
64
 
65
65
  class <<self
@@ -69,6 +69,8 @@ module Sprinkle
69
69
  end
70
70
  end
71
71
 
72
+ attributes :padding
73
+
72
74
  def initialize(package, description = '', &block) #:nodoc:
73
75
  raise 'Verify requires a block.' unless block
74
76
 
@@ -82,8 +84,6 @@ module Sprinkle
82
84
  end
83
85
 
84
86
  def process(roles, pre = false) #:nodoc:
85
- assert_delivery
86
-
87
87
  description = @description.empty? ? " (#{@package.name})" : @description
88
88
 
89
89
  if logger.debug?
@@ -1,3 +1,3 @@
1
1
  module Sprinkle
2
- Version = "0.5.2"
2
+ Version = "0.6.0"
3
3
  end
@@ -55,7 +55,7 @@ describe Sprinkle::Actors::Capistrano do
55
55
  end
56
56
 
57
57
  it 'should evaluate the block against the actor instance' do
58
- @actor.loaded_recipes.should include('cool gear')
58
+ @actor.loaded_recipes.should == ['cool gear']
59
59
  end
60
60
 
61
61
  end
@@ -63,7 +63,8 @@ describe Sprinkle::Actors::Capistrano do
63
63
  describe 'without a block' do
64
64
 
65
65
  it 'should automatically load the default capistrano configuration' do
66
- @cap.should_receive(:load).with('deploy').and_return
66
+ File.stub!(:exist?).with("Capfile").and_return true
67
+ @cap.should_receive(:load).with('Capfile').and_return
67
68
  end
68
69
 
69
70
  after do
@@ -77,15 +78,13 @@ describe Sprinkle::Actors::Capistrano do
77
78
  describe 'recipes' do
78
79
 
79
80
  it 'should add the recipe location to an internal store' do
80
- @cap = create_cap do
81
- recipes 'deploy'
82
- end
81
+ @cap = create_cap { recipes "deploy" }
83
82
  @cap.loaded_recipes.should == [ @recipes ]
84
83
  end
85
84
 
86
85
  it 'should load the given recipe' do
87
86
  @cap.should_receive(:load).with(@recipes).and_return
88
- create_cap
87
+ @cap = create_cap { recipes "deploy" }
89
88
  end
90
89
 
91
90
  end
@@ -131,6 +130,7 @@ describe Sprinkle::Actors::Capistrano do
131
130
  # pretend the package or installer has also added sudo
132
131
  @commands =["sudo op1"]
133
132
  @cap.stub(:sudo_command).and_return("sudo")
133
+ @cap.config.stub!(:fetch).and_return(:sudo)
134
134
  @cap.unstub!(:run)
135
135
  @cap.config.should_receive(:invoke_command).with('op1', :via => :sudo).ordered.and_return
136
136
  end
@@ -205,12 +205,13 @@ describe Sprinkle::Actors::Capistrano do
205
205
  @cap.config.stub!(:invoke_command).and_return
206
206
  end
207
207
 
208
- it 'should use sudo to invoke commands when so configured' do
209
- @cap.config.should_receive(:invoke_command).with('op1', :via => :sudo).ordered.and_return
210
- @cap.config.should_receive(:invoke_command).with('op2', :via => :sudo).ordered.and_return
208
+ it 'should run the supplied commands by default' do
209
+ @cap.config.should_receive(:invoke_command).with('op1', :via => :run).ordered.and_return
210
+ @cap.config.should_receive(:invoke_command).with('op2', :via => :run).ordered.and_return
211
211
  end
212
212
 
213
- it 'should run the supplied commands' do
213
+ it 'should use sudo to invoke commands when so configured' do
214
+ @cap.config.set :run_method, :sudo
214
215
  @cap.config.should_receive(:invoke_command).with('op1', :via => :sudo).ordered.and_return
215
216
  @cap.config.should_receive(:invoke_command).with('op2', :via => :sudo).ordered.and_return
216
217
  end
@@ -50,14 +50,14 @@ describe Sprinkle::Installers::Apt do
50
50
  @package = create_pkg "name", :use_sudo => true
51
51
  @installer = create_apt 'ruby'
52
52
  @install_commands = @installer.send :install_commands
53
- @install_commands.should =~ /sudo apt-get/
53
+ @install_commands.should =~ /sudo env/
54
54
  end
55
55
 
56
56
  it 'should use sudo if installer specifies' do
57
57
  @package = create_pkg "name", :use_sudo => false
58
58
  @installer = create_apt 'ruby', :sudo => true
59
59
  @install_commands = @installer.send :install_commands
60
- @install_commands.should =~ /sudo apt-get/
60
+ @install_commands.should =~ /sudo env/
61
61
  end
62
62
 
63
63
  it 'should invoke the apt installer for all specified packages' do
@@ -9,7 +9,7 @@ describe Sprinkle::Installers::Gem do
9
9
  end
10
10
 
11
11
  def create_gem(gem, version = nil, options = {}, &block)
12
- @package = mock(Sprinkle::Package, :name => gem, :version => version, :source => nil, :repository => nil)
12
+ @package = mock(Sprinkle::Package, :name => gem, :version => version)
13
13
  Sprinkle::Installers::Gem.new(@package, gem, options, &block)
14
14
  end
15
15
 
@@ -42,19 +42,18 @@ describe Sprinkle::Installers::Installer do
42
42
 
43
43
  it 'should accept an optional block to customize installers defaults' do
44
44
  @installer = create_installer do; prefix '/usr/local'; end
45
- @installer.prefix.first.should == '/usr/local'
45
+ @installer.prefix.should == '/usr/local'
46
46
  end
47
47
 
48
48
  it 'should override any deployment level defaults' do
49
49
  @installer = create_installer do; prefix '/usr/local'; end
50
50
  @installer.defaults(@deployment)
51
- @installer.prefix.first.should == '/usr/local'
51
+ @installer.prefix.should == '/usr/local'
52
52
  end
53
53
  end
54
54
  end
55
55
 
56
56
  describe 'during configuration' do
57
- # We just check to make sure it has the Sprinkle::Configurable method
58
57
  it 'should be configurable' do
59
58
  @installer.should respond_to(:defaults)
60
59
  end
@@ -126,41 +125,52 @@ describe Sprinkle::Installers::Installer do
126
125
 
127
126
  describe "with a pre command" do
128
127
 
129
- def create_installer_with_pre_command(cmd="")
128
+ def create_installer_with_pre_command(cmd = nil, &block)
130
129
  installer = Sprinkle::Installers::Installer.new @package do
131
- pre :install, cmd
130
+ pre :install, cmd if cmd
132
131
 
133
132
  def install_commands
134
133
  ["installer"]
135
134
  end
136
135
  end
137
-
136
+ installer.instance_eval &block if block
138
137
  installer.stub!(:puts).and_return
139
138
  installer.delivery = @delivery
140
139
  installer
141
140
  end
142
141
  before do
143
142
  @installer = create_installer_with_pre_command('run')
143
+ @package.stub!(:installers).and_return []
144
144
  end
145
145
  describe "string commands" do
146
146
  it "should insert the pre command for the specific package in the installation process" do
147
147
  @installer.send(:install_sequence).should == [ 'run', 'installer' ]
148
148
  end
149
- end
149
+ end
150
+ describe "block with their embeded installers" do
151
+ before(:each) do
152
+ @package = Package.new("package") do; end
153
+ @installer = create_installer_with_pre_command do
154
+ pre :install do
155
+ runner "b" do
156
+ pre(:install) { runner "a" }
157
+ post(:install) { runner "c" }
158
+ end
159
+ end
160
+ end
161
+ end
162
+ it "should properly execute pre and post blocks" do
163
+ @installer.send(:install_sequence).should == [ "a", "b", "c", 'installer' ]
164
+ end
165
+ end
150
166
  describe "blocks as commands" do
151
167
  before(:each) do
152
- @installer = Sprinkle::Installers::Installer.new @package do
168
+ @package = Package.new("package") do; end
169
+ @installer = create_installer_with_pre_command do
153
170
  pre :install do
154
171
  %w(a b c)
155
172
  end
156
-
157
- def install_commands
158
- ["installer"]
159
- end
160
173
  end
161
-
162
- @installer.stub!(:puts).and_return
163
- @installer.delivery = @delivery
164
174
  end
165
175
  it "should be able to store a block if it's the pre command" do
166
176
  @installer.send(:install_sequence).should == [ "a", "b", "c", 'installer' ]
@@ -89,6 +89,21 @@ MULTI
89
89
  end
90
90
  end
91
91
 
92
+ describe 'sending a string with special characters' do
93
+
94
+ it "should not escape an ampersand" do
95
+ @installer = create_text "bob & lucy", "/dev/mind/the-day-after"
96
+ @install_commands = @installer.send :install_commands
97
+ @install_commands.should == %q[/bin/echo -e 'bob & lucy' |tee -a /dev/mind/the-day-after]
98
+ end
99
+
100
+ it "should not escape a slash" do
101
+ @installer = create_text "bob/lucy", "/dev/mind/the-day-after"
102
+ @install_commands = @installer.send :install_commands
103
+ @install_commands.should == %q[/bin/echo -e 'bob/lucy' |tee -a /dev/mind/the-day-after]
104
+ end
105
+ end
106
+
92
107
  describe 'sending a string with single quotes' do
93
108
  before do
94
109
  @installer = create_text "I'm a string with a single quote", "/dev/mind/the-day-after"
@@ -47,10 +47,6 @@ describe Sprinkle::Installers::Rpm do
47
47
  @installer.send(:install_sequence).should == [ 'op1', 'rpm -Uvh ruby', 'op2' ]
48
48
  end
49
49
 
50
- it 'should install a specific version if defined' do
51
- pending
52
- end
53
-
54
50
  end
55
51
 
56
52
  end
@@ -76,35 +76,35 @@ describe Sprinkle::Installers::Source do
76
76
  describe 'customized configuration' do
77
77
 
78
78
  it 'should support specification of "enable" options' do
79
- @installer.enable.first.should == %w( headers ssl deflate so )
79
+ @installer.enable.should == %w( headers ssl deflate so )
80
80
  end
81
81
 
82
82
  it 'should support specification of "disable" options' do
83
- @installer.disable.first.should == %w( cache proxy rewrite )
83
+ @installer.disable.should == %w( cache proxy rewrite )
84
84
  end
85
85
 
86
86
  it 'should support specification of "with" options' do
87
- @installer.with.first.should == %w( debug extras )
87
+ @installer.with.should == %w( debug extras )
88
88
  end
89
89
 
90
90
  it 'should support specification of "without" options' do
91
- @installer.without.first.should == %w( fancyisms pandas )
91
+ @installer.without.should == %w( fancyisms pandas )
92
92
  end
93
93
 
94
94
  it 'should support specification of "option" options' do
95
- @installer.option.first.should == %w( foo bar baz )
95
+ @installer.option.should == %w( foo bar baz )
96
96
  end
97
97
 
98
98
  it 'should support customized build area' do
99
- @installer.prefix.first.should == '/usr/local'
99
+ @installer.prefix.should == '/usr/local'
100
100
  end
101
101
 
102
102
  it 'should support customized source area' do
103
- @installer.archives.first.should == '/usr/local/archives'
103
+ @installer.archives.should == '/usr/local/archives'
104
104
  end
105
105
 
106
106
  it 'should support customized install area' do
107
- @installer.builds.first.should == '/usr/local/builds'
107
+ @installer.builds.should == '/usr/local/builds'
108
108
  end
109
109
  end
110
110
 
@@ -285,9 +285,16 @@ describe Sprinkle::Installers::Source do
285
285
  it 'should run all pre-prepare commands' do
286
286
  @commands.each { |k, v| @installer.should_receive(:pre_commands).with(k).and_return(v) }
287
287
  end
288
+
289
+ it "should be logged" do
290
+ pending
291
+ end
288
292
 
289
293
  it 'should be run relative to the source build area' do
290
- @commands.each { |stage, command| @installer.send(:pre_commands, stage).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
294
+ [:prepare, :download, :extract].each { |stage, command|
295
+ @installer.send(:pre_commands, stage).first.should_not =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
296
+ [:configure, :build, :install].each { |stage, command|
297
+ @installer.send(:pre_commands, stage).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
291
298
  end
292
299
 
293
300
  after do
@@ -318,7 +325,10 @@ describe Sprinkle::Installers::Source do
318
325
  end
319
326
 
320
327
  it 'should be run relative to the source build area' do
321
- @commands.each { |stage, command| @installer.send(:post_commands, stage).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
328
+ [:prepare, :download].each { |stage, command|
329
+ @installer.send(:post_commands, stage).first.should_not =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
330
+ [:extract, :configure, :build, :install].each { |stage, command|
331
+ @installer.send(:post_commands, stage).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
322
332
  end
323
333
 
324
334
  after do
@@ -0,0 +1,30 @@
1
+ require File.expand_path("../../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Sprinkle::Installers::User do
4
+
5
+ before do
6
+ @package = mock(Sprinkle::Package, :name => 'spec')
7
+ @user = "bob"
8
+ end
9
+
10
+ def create_user(name, options = {}, &block)
11
+ Sprinkle::Installers::User.new "spec", name, options, &block
12
+ end
13
+
14
+ describe 'during installation' do
15
+
16
+ it "should invoke add user" do
17
+ @installer = create_user 'bob'
18
+ @install_commands = @installer.send :install_commands
19
+ @install_commands.should == "adduser --gecos ,,, bob"
20
+ end
21
+
22
+ it "should use actual gecos options if passed" do
23
+ @installer = create_user 'bob', :flags => "--gecos bob,,,"
24
+ @install_commands = @installer.send :install_commands
25
+ @install_commands.should == "adduser --gecos bob,,, bob"
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -140,17 +140,6 @@ describe Sprinkle::Verify do
140
140
  end
141
141
  end
142
142
 
143
- describe 'with configurations' do
144
- # Make sure it includes Sprinkle::Configurable
145
- it 'should respond to configurable methods' do
146
- @verification.should respond_to(:defaults)
147
- end
148
-
149
- it 'should default padding option to 4' do
150
- @verification.padding.should eql(4)
151
- end
152
- end
153
-
154
143
  describe 'with process' do
155
144
  it 'should raise an error when no delivery mechanism is set' do
156
145
  @verification.instance_variable_set(:@delivery, nil)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprinkle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-05-15 00:00:00.000000000 Z
13
+ date: 2013-05-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -169,15 +169,13 @@ files:
169
169
  - lib/sprinkle/actors/local.rb
170
170
  - lib/sprinkle/actors/ssh.rb
171
171
  - lib/sprinkle/actors/vlad.rb
172
- - lib/sprinkle/configurable.rb
173
172
  - lib/sprinkle/deployment.rb
174
173
  - lib/sprinkle/errors/pretty_failure.rb
175
174
  - lib/sprinkle/errors/remote_command_failure.rb
176
175
  - lib/sprinkle/errors/transfer_failure.rb
177
- - lib/sprinkle/extensions/arbitrary_options.rb
178
176
  - lib/sprinkle/extensions/array.rb
177
+ - lib/sprinkle/extensions/attributes.rb
179
178
  - lib/sprinkle/extensions/blank_slate.rb
180
- - lib/sprinkle/extensions/dsl_accessor.rb
181
179
  - lib/sprinkle/extensions/string.rb
182
180
  - lib/sprinkle/extensions/symbol.rb
183
181
  - lib/sprinkle/installers/apt.rb
@@ -235,7 +233,6 @@ files:
235
233
  - spec/sprinkle/actors/capistrano_spec.rb
236
234
  - spec/sprinkle/actors/local_spec.rb
237
235
  - spec/sprinkle/actors/ssh_spec.rb
238
- - spec/sprinkle/configurable_spec.rb
239
236
  - spec/sprinkle/deployment_spec.rb
240
237
  - spec/sprinkle/extensions/array_spec.rb
241
238
  - spec/sprinkle/extensions/string_spec.rb
@@ -261,6 +258,7 @@ files:
261
258
  - spec/sprinkle/installers/source_spec.rb
262
259
  - spec/sprinkle/installers/thor_spec.rb
263
260
  - spec/sprinkle/installers/transfer_spec.rb
261
+ - spec/sprinkle/installers/user_spec.rb
264
262
  - spec/sprinkle/installers/yum_spec.rb
265
263
  - spec/sprinkle/installers/zypper_spec.rb
266
264
  - spec/sprinkle/package_spec.rb
@@ -300,7 +298,6 @@ test_files:
300
298
  - spec/sprinkle/actors/capistrano_spec.rb
301
299
  - spec/sprinkle/actors/local_spec.rb
302
300
  - spec/sprinkle/actors/ssh_spec.rb
303
- - spec/sprinkle/configurable_spec.rb
304
301
  - spec/sprinkle/deployment_spec.rb
305
302
  - spec/sprinkle/extensions/array_spec.rb
306
303
  - spec/sprinkle/extensions/string_spec.rb
@@ -326,6 +323,7 @@ test_files:
326
323
  - spec/sprinkle/installers/source_spec.rb
327
324
  - spec/sprinkle/installers/thor_spec.rb
328
325
  - spec/sprinkle/installers/transfer_spec.rb
326
+ - spec/sprinkle/installers/user_spec.rb
329
327
  - spec/sprinkle/installers/yum_spec.rb
330
328
  - spec/sprinkle/installers/zypper_spec.rb
331
329
  - spec/sprinkle/package_spec.rb
@@ -1,32 +0,0 @@
1
- module Sprinkle
2
- #--
3
- # TODO: Possible documentation?
4
- #++
5
- module Configurable #:nodoc:
6
- attr_accessor :delivery
7
-
8
- def defaults(deployment)
9
- defaults = deployment.defaults[self.class.name.split(/::/).last.downcase.to_sym]
10
- self.instance_eval(&defaults) if defaults
11
- @delivery = deployment.style
12
- end
13
-
14
- def assert_delivery
15
- raise 'Unknown command delivery target' unless @delivery
16
- end
17
-
18
- def method_missing(sym, *args, &block)
19
- unless args.empty? # mutate if not set
20
- @options ||= {}
21
- @options[sym] = args unless @options[sym]
22
- end
23
-
24
- @options[sym] || @package.send(sym, *args, &block) # try the parents options if unknown
25
- end
26
-
27
- # both nil and false should return false
28
- def option?(sym)
29
- !!@options[sym]
30
- end
31
- end
32
- end
@@ -1,10 +0,0 @@
1
- module ArbitraryOptions #:nodoc:
2
- def self.included(base)
3
- base.alias_method_chain :method_missing, :arbitrary_options
4
- end
5
-
6
- def method_missing_with_arbitrary_options(sym, *args, &block)
7
- self.class.dsl_accessor sym
8
- send(sym, *args, &block)
9
- end
10
- end
@@ -1,15 +0,0 @@
1
- class Module #:nodoc:
2
- def dsl_accessor(*symbols)
3
- symbols.each do |sym|
4
- class_eval %{
5
- def #{sym}(*val)
6
- if val.empty?
7
- @#{sym}
8
- else
9
- @#{sym} = val.size == 1 ? val[0] : val
10
- end
11
- end
12
- }
13
- end
14
- end
15
- end
@@ -1,47 +0,0 @@
1
- require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
-
3
- describe Sprinkle::Configurable do
4
- module MyPrefix
5
- class Configurable
6
- include Sprinkle::Configurable
7
- end
8
- end
9
-
10
- before do
11
- @configurable = MyPrefix::Configurable.new
12
- @default = Proc.new { }
13
- @defaults = { :configurable => @default }
14
- @deployment = Object.new
15
- @deployment.stub!(:defaults).and_return(@defaults)
16
- @deployment.stub!(:style)
17
- end
18
-
19
- it 'should be configurable via external defaults' do
20
- @configurable.should respond_to(:defaults)
21
- end
22
-
23
- it 'should select the defaults for the particular concrete installer class' do
24
- @deployment.should_receive(:defaults).and_return(@defaults)
25
- @defaults.should_receive(:[]).with(:configurable).and_return(@default)
26
- end
27
-
28
- it 'should configure the installer delivery mechansim' do
29
- @configurable.should_receive(:instance_eval)
30
- end
31
-
32
- it 'should maintain an options hash set arbitrarily via method missing' do
33
- @configurable.instance_eval do
34
- hsv 'gts'
35
- end
36
- @configurable.hsv.first.should == 'gts'
37
- end
38
-
39
- it 'should allow the delivery instance variable to be accessed' do
40
- @configurable.delivery = "string"
41
- @configurable.instance_variable_get(:@delivery).should eql("string")
42
- end
43
-
44
- after do
45
- @configurable.defaults(@deployment)
46
- end
47
- end