sprinkle 0.7.6.2 → 0.7.7

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.
@@ -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: