sprinkle 0.7.6.2 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@ PATH
3
3
  specs:
4
4
  sprinkle (0.7.6.2)
5
5
  activesupport (>= 2.0.2)
6
- capistrano (~> 2.5.5)
6
+ capistrano (>= 2.5.5, < 3)
7
7
  erubis (>= 2.7.0)
8
8
  highline (>= 1.4.0)
9
9
  open4 (>= 1.1.0)
@@ -28,12 +28,12 @@ GEM
28
28
  i18n (= 0.6.1)
29
29
  multi_json (~> 1.0)
30
30
  builder (3.0.4)
31
- capistrano (2.5.21)
31
+ capistrano (2.15.5)
32
32
  highline
33
33
  net-scp (>= 1.0.0)
34
34
  net-sftp (>= 2.0.0)
35
35
  net-ssh (>= 2.0.14)
36
- net-ssh-gateway (>= 1.0.0)
36
+ net-ssh-gateway (>= 1.1.0)
37
37
  coderay (1.0.9)
38
38
  diff-lcs (1.2.4)
39
39
  erubis (2.7.0)
@@ -46,19 +46,19 @@ Options are:
46
46
  BANNER
47
47
  opts.separator ""
48
48
  opts.on("-s", "--script=PATH", String,
49
- "Path to a sprinkle script to run") { |v| OPTIONS[:path] = v }
49
+ "path to a sprinkle script to run") { |v| OPTIONS[:path] = v }
50
50
  opts.on("--only [ROLE]", String,
51
- "Only run sprinkle policies for the specified role") { |v| OPTIONS[:only_role] = v }
51
+ "only run sprinkle policies for given role") { |v| OPTIONS[:only_role] = v }
52
52
  opts.on("-t", "--test",
53
- "Process but don't perform any actions") { |v| OPTIONS[:testing] = v }
54
- opts.on("-v", "--verbose",
55
- "Verbose output") { |v| OPTIONS[:verbose] = v }
53
+ "process but don't perform any actions","(this does not connect to any servers)") { |v| OPTIONS[:testing] = v }
56
54
  opts.on("-c", "--cloud",
57
- "Show powder cloud, ie. package hierarchy and installation order") { |v| OPTIONS[:cloud] = v }
55
+ "show powder cloud, package hierarchy","and installation order") { |v| OPTIONS[:cloud] = v }
58
56
  opts.on("-f", "--force",
59
- "Force installation of all packages even if it is detected that it has been previously installed") { |v| OPTIONS[:force] = v }
57
+ "force installation of all packages","by skipping pre-verify checks.") { |v| OPTIONS[:force] = v }
58
+ opts.on("-v", "--verbose",
59
+ "verbose output") { |v| OPTIONS[:verbose] = v }
60
60
  opts.on("-h", "--help",
61
- "Show this help message.") { puts opts; exit }
61
+ "show this help message") { puts opts; exit }
62
62
  opts.parse!(ARGV)
63
63
 
64
64
  if MANDATORY_OPTIONS && MANDATORY_OPTIONS.find { |option| OPTIONS[option.to_sym].nil? }
@@ -25,6 +25,8 @@ module Sprinkle
25
25
  @config = ::Capistrano::Configuration.new
26
26
  @config.logger.level = Sprinkle::OPTIONS[:verbose] ? ::Capistrano::Logger::INFO : ::Capistrano::Logger::IMPORTANT
27
27
  @config.set(:password) { ::Capistrano::CLI.password_prompt }
28
+ # default sudo to false, we must turn it on
29
+ @config.set(:run_method) { @config.fetch(:use_sudo, false) ? :sudo : :run }
28
30
 
29
31
  @config.set(:_sprinkle_actor, self)
30
32
 
@@ -40,7 +42,7 @@ module Sprinkle
40
42
  end
41
43
 
42
44
  def sudo? #:nodoc:
43
- @config.fetch(:run_method, :run) == :sudo
45
+ @config.fetch(:run_method) == :sudo
44
46
  end
45
47
 
46
48
  def sudo_command #:nodoc:
@@ -98,7 +100,7 @@ module Sprinkle
98
100
  @log_recorder = log_recorder = Sprinkle::Utility::LogRecorder.new
99
101
  commands = commands.map {|x| rewrite_command(x)}
100
102
  define_task(name, roles) do
101
- via = fetch(:run_method, :run)
103
+ via = fetch(:run_method)
102
104
  commands.each do |command|
103
105
  if command.is_a? Commands::Transfer
104
106
  upload command.source, command.destination, :via => :scp,
@@ -123,7 +125,7 @@ module Sprinkle
123
125
  # rip out any double sudos from the beginning of the command
124
126
  def rewrite_command(cmd)
125
127
  return cmd if cmd.is_a?(Symbol)
126
- via = @config.fetch(:run_method, :run)
128
+ via = @config.fetch(:run_method)
127
129
  if via == :sudo and cmd =~ /^#{sudo_command}/
128
130
  cmd.gsub(/^#{sudo_command}\s?/,"")
129
131
  else
@@ -13,13 +13,13 @@ module Sprinkle
13
13
  # This example will download archive.tar.gz to /home/user/sources and then
14
14
  # extract it into /home/user/local.
15
15
  class Binary < Installer
16
-
16
+
17
17
  api do
18
18
  def binary(source, options = {}, &block)
19
19
  install Binary.new(self, source, options, &block)
20
20
  end
21
21
  end
22
-
22
+
23
23
  def initialize(parent, binary_archive, options = {}, &block) #:nodoc:
24
24
  @binary_archive = binary_archive
25
25
  super parent, options, &block
@@ -35,7 +35,7 @@ module Sprinkle
35
35
 
36
36
  def install_commands #:nodoc:
37
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}'\""
38
+ commands << "bash -c \"cd #{@options[:prefix]} && #{sudo_cmd} #{extract_command} '#{@options[:archives]}/#{archive_name}'\""
39
39
  end
40
40
 
41
41
  def archive_name #:nodoc:
@@ -49,7 +49,7 @@ module Sprinkle
49
49
  # rubygems 0.9.5+ installs dependencies by default, and does platform selection
50
50
 
51
51
  def install_commands #:nodoc:
52
- cmd = "gem install #{gem}"
52
+ cmd = "#{sudo_cmd}gem install #{gem}"
53
53
  cmd << " --version '#{version}'" if version
54
54
  cmd << " --source #{source}" if source
55
55
  cmd << " --install-dir #{repository}" if option?(:repository)
@@ -20,7 +20,7 @@ module Sprinkle
20
20
 
21
21
  verify_api do
22
22
  def has_group(group)
23
- @commands << "id -g #{group}"
23
+ @commands << "egrep -i \"^#{group}:\" /etc/group"
24
24
  end
25
25
  end
26
26
 
@@ -14,7 +14,7 @@ module Sprinkle
14
14
  # pre/post installation hooks. This gives you the ability to specify
15
15
  # commands to run before and after an installation takes place.
16
16
  # There are three ways to specify a pre/post hook.
17
-
17
+ #
18
18
  # Note about sudo:
19
19
  # When using the Capistrano actor all commands by default are run using
20
20
  # sudo (unless your Capfile includes "set :use_sudo, false"). If you wish
@@ -143,7 +143,7 @@ module Sprinkle
143
143
  @verifications = []
144
144
  @install_queues ||= [[]]
145
145
  @block = block
146
- @use_sudo = false
146
+ @use_sudo = nil
147
147
  @version = nil
148
148
  # this should probably not be done twice
149
149
  self.instance_eval(&block)
@@ -167,7 +167,7 @@ module Sprinkle
167
167
  end
168
168
 
169
169
  def sudo?
170
- @use_sudo
170
+ !!@use_sudo
171
171
  end
172
172
 
173
173
  def use_sudo(flag=true)
@@ -204,14 +204,10 @@ module Sprinkle
204
204
  def verify(description = '', &block)
205
205
  @verifications << Sprinkle::Verify.new(self, description, &block)
206
206
  end
207
-
207
+
208
208
  def process(deployment, roles)
209
- logger.info " * #{name}"
209
+ output_name
210
210
  return if meta_package?
211
- opts.each_with_index do |(k, v), index|
212
- branch = (index == opts.size - 1) ? "└" : "├"
213
- logger.debug " #{branch}─ #{k}: #{v}"
214
- end
215
211
 
216
212
  # Run a pre-test to see if the software is already installed. If so,
217
213
  # we can skip it, unless we have the force option turned on!
@@ -246,7 +242,7 @@ module Sprinkle
246
242
 
247
243
  @verifications.each do |v|
248
244
  v.defaults(deployment)
249
- v.process(roles)
245
+ v.process(roles, pre)
250
246
  end
251
247
  end
252
248
 
@@ -302,6 +298,18 @@ module Sprinkle
302
298
  end
303
299
 
304
300
  private
301
+
302
+ def output_name
303
+ logger.info " * #{name} #{output_arguments}"
304
+ opts.each_with_index do |(k, v), index|
305
+ branch = (index == opts.size - 1) ? "└" : "├"
306
+ logger.debug " #{branch}─ #{k}: #{v}"
307
+ end
308
+ end
309
+
310
+ def output_arguments
311
+ (opts.empty? or Sprinkle::OPTIONS[:verbose]) ? "" : opts.inspect.gsub(/^\{(.*)\}$/, "\\1" )
312
+ end
305
313
 
306
314
  def add_dependencies(packages, kind)
307
315
  opts = packages.extract_options!
@@ -7,13 +7,12 @@ module Sprinkle::Package
7
7
  else
8
8
  package = choose do |menu|
9
9
  menu.prompt = "Multiple choices exist for virtual package #{name}"
10
- menu.choices( *packages.collect(&:to_s) )
10
+ packages.each do |pkg|
11
+ menu.choice(pkg.to_s) { pkg; }
12
+ end
11
13
  end
12
- package = Sprinkle::Package::PACKAGES.first(package)
13
14
  end
14
-
15
15
  cloud_info "Selecting #{package.to_s} for virtual package #{name}"
16
-
17
16
  package
18
17
  end
19
18
 
@@ -52,6 +52,31 @@ module Sprinkle
52
52
  # The capistrano and vlad syntax is the same for that. If you're using a
53
53
  # custom actor, you may have to do it differently.
54
54
  #
55
+ # == Requiring a package more than once with different options
56
+ #
57
+ # This works exactly as you might expect:
58
+ #
59
+ # policy :bootstrap, :roles => :app do
60
+ # require :user_settings, :for => "john"
61
+ # require :user_settings, :for => "suzy"
62
+ # require :user_settings, :for => "dorothy"
63
+ # end
64
+ #
65
+ # Multiple requires for a package with no options will be
66
+ # collapsed; that package will be installed once.
67
+ #
68
+ # policy :apache, :roles => :app do
69
+ # require :devtools
70
+ # ...
71
+ # end
72
+ # policy :git, :roles => :app do
73
+ # require :devtools
74
+ # ...
75
+ # end
76
+ #
77
+ # In this example devtools will only be installed once, prior to
78
+ # apache and git.
79
+ #
55
80
  # == Multiple Policies
56
81
  #
57
82
  # You may specify as many policies as you'd like. If the packages you're
@@ -92,38 +117,45 @@ module Sprinkle
92
117
  def process(deployment) #:nodoc:
93
118
  raise NoMatchingServersError.new(@name, @roles) unless deployment.style.servers_for_role?(@roles)
94
119
 
95
- all = []
96
-
97
120
  logger.info "[#{name}]"
98
121
 
99
- cloud_info "--> Cloud hierarchy for policy #{@name}"
100
-
101
- @packages.each do |p, args|
102
- cloud_info " * requires package #{p}"
103
-
104
- opts = args.clone.extract_options!
105
- package = Sprinkle::Package::PACKAGES.find_all(p, opts)
106
- raise MissingPackageError.new(p) unless package.any?
107
- package = Sprinkle::Package::Chooser.select_package(p, package) if package.is_a? Array # handle virtual package selection
108
- # get an instance of the package and pass our config options
109
- package = package.instance(*args)
110
-
111
- tree = package.tree do |parent, child, depth|
112
- indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
113
- end
114
-
115
- all << tree
116
- end
117
-
118
- normalize(all).each do |package|
122
+ package_install_tree.each do |package|
119
123
  package.process(deployment, @roles)
120
124
  end
121
125
  end
126
+
127
+ def package_install_tree
128
+ @install_tree ||= normalize(tree)
129
+ end
122
130
 
123
131
  private
132
+
133
+ def tree()
134
+ all = []
135
+
136
+ cloud_info "--> Cloud hierarchy for policy #{@name}"
137
+
138
+ @packages.each do |p, args|
139
+ cloud_info " * requires package #{p}"
140
+
141
+ opts = args.clone.extract_options!
142
+ package = Sprinkle::Package::PACKAGES.find_all(p, opts)
143
+ raise MissingPackageError.new(p) unless package.any?
144
+ package = Sprinkle::Package::Chooser.select_package(p, package) if package.is_a? Array # handle virtual package selection
145
+ # get an instance of the package and pass our config options
146
+ package = package.instance(*args)
147
+ tree = package.tree do |parent, child, depth|
148
+ indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
149
+ end
150
+
151
+ all << tree
152
+ end
153
+ all
154
+
155
+ end
124
156
 
125
157
  def normalize(all, &block)
126
- all = all.flatten.uniq {|x| [x.name, x.version] }
158
+ all = all.flatten.uniq {|x| [x.name, x.version, x.opts] }
127
159
  cloud_info "--> Normalized installation order for all packages: #{all.collect(&:name).join(', ')}\n"
128
160
  all
129
161
  end
@@ -62,7 +62,7 @@ module Sprinkle
62
62
  include Sprinkle::Attributes
63
63
  include Sprinkle::Package::Rendering::Helpers
64
64
  include Sprinkle::Sudo
65
- attr_accessor :package, :description, :commands, :options #:nodoc:
65
+ attr_accessor :package, :description, :options #:nodoc:
66
66
 
67
67
  delegate :opts, :to => :package
68
68
  delegate :args, :to => :package
@@ -87,8 +87,19 @@ module Sprinkle
87
87
  @options ||= {}
88
88
  @options[:padding] = 4
89
89
  @delivery = nil
90
-
91
- self.instance_eval(&block)
90
+ @block = block
91
+ end
92
+
93
+ def commands
94
+ prepare
95
+ @commands
96
+ end
97
+
98
+ def prepare
99
+ return if @prepared
100
+ @commands = []
101
+ self.instance_eval(&@block)
102
+ @prepared = true
92
103
  end
93
104
 
94
105
  def runner(*cmds)
@@ -109,7 +120,10 @@ module Sprinkle
109
120
  logger.debug "#{@package.name}#{description} verification sequence: #{@commands.join('; ')} for roles: #{roles}\n"
110
121
  end
111
122
 
112
- unless Sprinkle::OPTIONS[:testing]
123
+ if Sprinkle::OPTIONS[:testing]
124
+ # always fail when testing to force an install
125
+ raise Sprinkle::VerificationFailed.new(@package, description) if pre
126
+ else
113
127
  logger.debug "#{" " * @options[:padding]}--> Verifying #{description}..."
114
128
 
115
129
  unless @delivery.verify(self, roles)
@@ -1,3 +1,3 @@
1
1
  module Sprinkle
2
- Version = "0.7.6.2"
2
+ Version = "0.7.7"
3
3
  end
@@ -30,7 +30,7 @@ describe Sprinkle::Actors::Local do
30
30
 
31
31
  before do
32
32
  @verifier = Sprinkle::Verify::new(@package) {}
33
- @verifier.commands += ["test","test"]
33
+ @verifier.commands.concat ["test","test"]
34
34
  @roles = %w( app )
35
35
  @name = 'name'
36
36
  end
@@ -3,7 +3,7 @@ require File.expand_path("../../spec_helper", File.dirname(__FILE__))
3
3
  describe Sprinkle::Installers::Binary do
4
4
  include Sprinkle::Deployment
5
5
 
6
- def create_context(source = 'http://www.example.com/archive.tar.gz')
6
+ def create_context(source = 'http://www.example.com/archive.tar.gz', sudo = false)
7
7
  deployment = deployment do
8
8
  delivery :capistrano
9
9
  binary source do
@@ -12,7 +12,7 @@ describe Sprinkle::Installers::Binary do
12
12
  end
13
13
  end
14
14
 
15
- installer = create_binary source do
15
+ installer = create_binary source, sudo do
16
16
  prefix '/prefix/directory'
17
17
  archives '/archives/directory'
18
18
  end
@@ -22,8 +22,8 @@ describe Sprinkle::Installers::Binary do
22
22
  [source, deployment, installer]
23
23
  end
24
24
 
25
- def create_binary(binary, version = nil, &block)
26
- @package = double(Sprinkle::Package, :name => 'package', :version => version)
25
+ def create_binary(binary, sudo, version = nil, &block)
26
+ @package ||= double(Sprinkle::Package, :name => 'package', :version => version, :sudo? => sudo)
27
27
  Sprinkle::Installers::Binary.new(@package, binary, &block)
28
28
  end
29
29
 
@@ -59,6 +59,16 @@ describe Sprinkle::Installers::Binary do
59
59
  end
60
60
  end
61
61
 
62
+ describe "binary#install_commands", "with sudo support" do
63
+ before do
64
+ @binary, @deployment, @installer = create_context 'http://www.example.com/archive.tar.gz', true
65
+ end
66
+
67
+ it "should sudo the command when required" do
68
+ @installer.send(:install_commands)[1].should =~ /sudo/
69
+ end
70
+ end
71
+
62
72
  describe "when source contains spaces (%20's) in path" do
63
73
  before do
64
74
  _, _, @installer = create_context('http://c758482.r82.cf2.rackcdn.com/Sublime%20Text%202.0.1%20x64.tar.bz2')
@@ -86,6 +86,17 @@ describe Sprinkle::Installers::Gem do
86
86
 
87
87
  end
88
88
 
89
+ describe "with sudo" do
90
+ before do
91
+ @installer = create_gem @gem, nil, :sudo => true
92
+ end
93
+
94
+ it 'should call sudo' do
95
+ @installer.send(:install_commands).should == "sudo gem install #{@gem} --no-rdoc --no-ri"
96
+ end
97
+
98
+ end
99
+
89
100
  describe 'with build flags' do
90
101
 
91
102
  before do
@@ -397,7 +397,7 @@ CODE
397
397
  it 'should request _each_ verification to process' do
398
398
  @pkg.verifications.each do |v|
399
399
  v.stub(:defaults)
400
- v.should_receive(:process).with(@roles).once
400
+ v.should_receive(:process).with(@roles, false).once
401
401
  end
402
402
  end
403
403
 
@@ -51,6 +51,35 @@ describe Sprinkle::Policy do
51
51
  end
52
52
 
53
53
  end
54
+
55
+ describe 'with the same package multiple times' do
56
+ include Sprinkle::Package
57
+
58
+ before do
59
+ @deployment = double(Sprinkle::Deployment)
60
+ actor = double(:servers_for_role? => true)
61
+ @deployment.stub(:style).and_return(actor)
62
+ Sprinkle::Package::PACKAGES.clear # reset full package list before each spec is run
63
+
64
+ @user = package :user do; end
65
+
66
+ @policy = policy :test, :roles => :app do
67
+ requires :user, :name => "josh"
68
+ requires :user, :name => "bill"
69
+ end
70
+ end
71
+
72
+ it "should call process on both users" do
73
+ (all=@policy.package_install_tree).size.should == 2
74
+ all.each do |p|
75
+ p.should_receive(:process).and_return
76
+ end
77
+ end
78
+
79
+ after do
80
+ @policy.process(@deployment)
81
+ end
82
+ end
54
83
 
55
84
  describe 'with packages' do
56
85
  include Sprinkle::Package
@@ -72,7 +101,7 @@ describe Sprinkle::Policy do
72
101
  @d.stub(:instance).and_return(@d)
73
102
 
74
103
  @policy = policy :test, :roles => :app do; requires :a; end
75
- $terminal.stub(:choose).and_return(:c) # stub out highline asking questions
104
+ $terminal.stub(:choose).and_return(@c) # stub out highline asking questions
76
105
  end
77
106
 
78
107
  describe 'when applying' do
@@ -123,7 +152,7 @@ describe Sprinkle::Policy do
123
152
 
124
153
  it 'should ask the user for the concrete package implementation to use for a virtual one when more than one possible choice exists' do
125
154
  @policy = policy :virtual, :roles => :app do; requires :abc; end
126
- $terminal.should_receive(:choose).and_return(:c)
155
+ $terminal.should_receive(:choose).and_return(@c)
127
156
  @c.should_receive(:process)
128
157
  end
129
158
 
@@ -65,7 +65,7 @@ describe Sprinkle::Verify do
65
65
  end
66
66
  end
67
67
  @verification = @package.verifications[0]
68
- @delivery = double(Sprinkle::Deployment, :process => true, :sudo_command => "sudo")
68
+ @delivery = double(Sprinkle::Deployment, :process => true, :sudo_command => "sudo", :sudo? => false)
69
69
  @verification.delivery = @delivery
70
70
  end
71
71
 
@@ -136,8 +136,8 @@ describe Sprinkle::Verify do
136
136
  @verification.commands.should include('id bob')
137
137
  end
138
138
 
139
- it 'should use id to check for group' do
140
- @verification.commands.should include('id -g bobgroup')
139
+ it 'should use egrep to check a group exists' do
140
+ @verification.commands.should include('egrep -i "^bobgroup:" /etc/group')
141
141
  end
142
142
 
143
143
  it 'should do a "test -L" to check something is a symbolic link' do
@@ -34,7 +34,7 @@ Gem::Specification.new do |s|
34
34
  s.add_runtime_dependency(%q<open4>, [">= 1.1.0"])
35
35
  s.add_runtime_dependency(%q<activesupport>, [">= 2.0.2"])
36
36
  s.add_runtime_dependency(%q<highline>, [">= 1.4.0"])
37
- s.add_runtime_dependency(%q<capistrano>, ["~> 2.5.5"])
37
+ s.add_runtime_dependency(%q<capistrano>, [">= 2.5.5", '< 3'])
38
38
 
39
39
  end
40
40
 
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.7.6.2
4
+ version: 0.7.7
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-10-15 00:00:00.000000000 Z
13
+ date: 2014-07-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -129,17 +129,23 @@ dependencies:
129
129
  requirement: !ruby/object:Gem::Requirement
130
130
  none: false
131
131
  requirements:
132
- - - ~>
132
+ - - ! '>='
133
133
  - !ruby/object:Gem::Version
134
134
  version: 2.5.5
135
+ - - <
136
+ - !ruby/object:Gem::Version
137
+ version: '3'
135
138
  type: :runtime
136
139
  prerelease: false
137
140
  version_requirements: !ruby/object:Gem::Requirement
138
141
  none: false
139
142
  requirements:
140
- - - ~>
143
+ - - ! '>='
141
144
  - !ruby/object:Gem::Version
142
145
  version: 2.5.5
146
+ - - <
147
+ - !ruby/object:Gem::Version
148
+ version: '3'
143
149
  description: Ruby DSL based software provisioning tool
144
150
  email: crafterm@redartisan.com
145
151
  executables: