sprinkle 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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