sprinkle 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sprinkle (0.7.4)
4
+ sprinkle (0.7.6)
5
5
  activesupport (>= 2.0.2)
6
6
  capistrano (>= 2.5.5)
7
7
  erubis (>= 2.7.0)
@@ -56,8 +56,11 @@ end
56
56
  deployment do
57
57
 
58
58
  # mechanism for deployment
59
- delivery :capistrano do
60
- recipes 'deploy'
59
+ # delivery :capistrano do
60
+ # recipes 'deploy'
61
+ # end
62
+ delivery :dummy do
63
+ role :app, "test"
61
64
  end
62
65
 
63
66
  # source based package installer defaults
@@ -17,6 +17,8 @@ def require_all(*args) # :nodoc:
17
17
  Dir[File.dirname(__FILE__) + "/sprinkle/#{f}"].each { |e| require e } }
18
18
  end
19
19
 
20
+ $LOAD_PATH << File.dirname(__FILE__)
21
+
20
22
  require 'sprinkle/version'
21
23
 
22
24
  require_all "extensions/*.rb"
@@ -100,11 +100,10 @@ module Sprinkle
100
100
  define_task(name, roles) do
101
101
  via = fetch(:run_method, :run)
102
102
  commands.each do |command|
103
- if command == :TRANSFER
104
- opts.reverse_merge!(:recursive => true)
105
- upload inst.sourcepath, inst.destination, :via => :scp,
106
- :recursive => opts[:recursive]
107
- elsif command == :RECONNECT
103
+ if command.is_a? Commands::Transfer
104
+ upload command.source, command.destination, :via => :scp,
105
+ :recursive => command.recursive?
106
+ elsif command.is_a? Commands::Reconnect
108
107
  teardown_connections_to(sessions.keys)
109
108
  else
110
109
  # this reset the log
@@ -4,6 +4,8 @@ require 'pp'
4
4
  module Sprinkle
5
5
  module Actors
6
6
  class Dummy < Actor #:nodoc:
7
+
8
+ attr_accessor :per_host
7
9
 
8
10
  def initialize(&block) #:nodoc:
9
11
  # @config.set(:_sprinkle_actor, self)
@@ -23,6 +25,7 @@ module Sprinkle
23
25
  end
24
26
 
25
27
  def install(installer, roles, opts={})
28
+ @installer = installer
26
29
  if self.per_host=opts.delete(:per_host)
27
30
  servers_per_role(roles).each do |server|
28
31
  installer.reconfigure_for(server)
@@ -45,10 +48,16 @@ module Sprinkle
45
48
  def servers_per_role(role)
46
49
  @roles[role]
47
50
  end
51
+
52
+ def print_command(cmd)
53
+ puts cmd.inspect
54
+ end
48
55
 
49
56
  def process(name, commands, roles, opts = {}) #:nodoc:
50
57
  # puts "PROCESS: #{name} on #{roles}"
51
- pp commands
58
+ commands.each do |cmd|
59
+ print_command(cmd)
60
+ end
52
61
  # return false if suppress_and_return_failures
53
62
  true
54
63
  end
@@ -53,11 +53,11 @@ module Sprinkle
53
53
  def process(name, commands, roles, opts = {}) #:nodoc:
54
54
  @log_recorder = Sprinkle::Utility::LogRecorder.new
55
55
  commands.each do |command|
56
- if command == :RECONNECT
56
+ if command.is_a?(Commands::Reconnect)
57
57
  res = 0
58
- elsif command == :TRANSFER
59
- res = transfer(@installer.sourcepath, @installer.destination, roles,
60
- :recursive => @installer.options[:recursive])
58
+ elsif command.is_a?(Commands::Transfer)
59
+ res = transfer(command.source, command.destination, roles,
60
+ :recursive => command.recursive?)
61
61
  else
62
62
  res = run_command command
63
63
  end
@@ -162,11 +162,11 @@ module Sprinkle
162
162
  def execute_on_host(commands,host) #:nodoc:
163
163
  prepare_commands(commands).each do |cmd|
164
164
  case cmd
165
- when :RECONNECT
165
+ when cmd.is_a?(Commands::Reconnect) then
166
166
  reconnect host
167
- when :TRANSFER
168
- transfer_to_host(@installer.sourcepath, @installer.destination, host,
169
- :recursive => @installer.options[:recursive])
167
+ when cmd.is_a?(Commands::Transfer) then
168
+ transfer_to_host(cmd.source, cmd.destination, host,
169
+ :recursive => cmd.recursive?)
170
170
  else
171
171
  run_command cmd, host
172
172
  end
@@ -0,0 +1,23 @@
1
+ module Sprinkle
2
+ module Commands
3
+ class Command
4
+
5
+ def initialize(str, opts = {})
6
+ @sudo = opts[:sudo]
7
+ @str = str
8
+ # this is a dummy class for now, not intended to be used directly
9
+ raise
10
+ end
11
+
12
+ def sudo?
13
+ @sudo
14
+ end
15
+
16
+ def string
17
+ # TODO: sudo
18
+ @str
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Sprinkle
2
+ module Commands
3
+ class Reconnect < Command
4
+
5
+ def initialize()
6
+ end
7
+
8
+ def inspect
9
+ ":RECONNECT"
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ module Sprinkle
2
+ module Commands
3
+ class Transfer < Command
4
+
5
+ attr_reader :source, :destination, :opts
6
+
7
+ def initialize(source, destination, opts={})
8
+ @source = source
9
+ @destination = destination
10
+ @opts = opts
11
+ end
12
+
13
+ def recursive?
14
+ !!@opts[:recursive]
15
+ end
16
+
17
+ def inspect
18
+ ":TRANSFER, src: #{source}, dest: #{destination}, opts: #{@opts.inspect}"
19
+ end
20
+
21
+ def eql?(a,b)
22
+ a.source == b.source &&
23
+ a.destionation == b.destination &&
24
+ a.opts == b.opts
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -32,8 +32,23 @@ module Sprinkle
32
32
  # @nginx_port = 8080
33
33
  # file '/etc/nginx.conf',
34
34
  # :contents => render("nginx.conf")
35
- # # ./templates/nginx.conf.erb or
36
- # # ./templates/nginx.conf should contain the erb template
35
+ # # where [cwd] is the current working dir you're running sprinkle from
36
+ # # [cwd]/templates/nginx.conf.erb or
37
+ # # [cwd]/templates/nginx.conf should contain the erb template
38
+ # end
39
+ #
40
+ # You can also tell the package where to look for templates, so that if you have
41
+ # a complex package hierarchy such as:
42
+ #
43
+ # .../packages/p/postfix.rb
44
+ # .../packages/p/postfix/templates/main.cf.erb
45
+ #
46
+ # package :postfix do
47
+ # template_search_path File.dirname(__FILE__)
48
+ # file '/etc/postfix/main.cf', :contents => render("main.cf")
49
+ # # searches for:
50
+ # # ../packages/p/main.cf[.erb]
51
+ # # ../packages/p/templates/main.cf[.erb]
37
52
  # end
38
53
  class FileInstaller < Installer
39
54
  attr_reader :sourcepath, :destination, :contents #:nodoc:
@@ -60,7 +75,7 @@ module Sprinkle
60
75
  end
61
76
 
62
77
  def install_commands #:nodoc:
63
- :TRANSFER
78
+ Commands::Transfer.new(sourcepath, destination)
64
79
  end
65
80
 
66
81
  # calls chown own to set the file ownership
@@ -87,12 +102,16 @@ module Sprinkle
87
102
  end
88
103
 
89
104
  def setup_source
90
- @file=Tempfile.new(@package.name.to_s)
91
- @file.print(@contents)
105
+ @file = Tempfile.new(@package.name.to_s)
106
+ @file.print @contents
92
107
  @file.close
93
108
  @sourcepath = @file.path
94
109
  end
95
110
 
111
+ def post_process
112
+ @file.unlink
113
+ end
114
+
96
115
  end
97
116
  end
98
117
  end
@@ -130,6 +130,10 @@ module Sprinkle
130
130
  return false
131
131
  end
132
132
 
133
+ # Called right after processing, can be used for local cleanup such
134
+ # as removing any temporary files created on the local system, etc
135
+ def post_process; end
136
+
133
137
  # Called right before an installer is exected, can be used for logging
134
138
  # and announcing what is about to happen
135
139
  def announce; end
@@ -144,6 +148,7 @@ module Sprinkle
144
148
  logger.debug " --> Running #{self.class.name} for roles: #{roles}"
145
149
  @delivery.install(self, roles, :per_host => per_host?)
146
150
  end
151
+ post_process
147
152
  end
148
153
 
149
154
  # More complicated installers that have different stages, and require pre/post commands
@@ -0,0 +1,82 @@
1
+ module Sprinkle
2
+ module Installers
3
+ # = Pecl extension installed
4
+ #
5
+ # Installs the specified pecl extension
6
+ #
7
+ # == Example Usage
8
+ #
9
+ # package :php_stuff do
10
+ # pecl 'mongo'
11
+ # verify { has_pecl 'mongo' }
12
+ # end
13
+ #
14
+ # You can optionally pass a version number to both `pecl` and `has_pecl`:
15
+ #
16
+ # package :php_stuff do
17
+ # pecl 'mongo', :version => "1.4.3"
18
+ # verify { has_pecl 'mongo', :version => "1.4.3" }
19
+ # end
20
+ #
21
+ # Some extensions need an ini file. You can have that generated, by passing the `:ini_file` option:
22
+ #
23
+ # package :php_stuff do
24
+ # pecl 'mongo', :ini_file => true
25
+ # end
26
+ #
27
+ # If you need more fine grained control of the location or contents of the ini file, use:
28
+ #
29
+ # package :php_stuff do
30
+ # pecl 'mongo', :ini_file => { :path => "/etc/php5/apache2/php.ini",
31
+ # :content => "extension=mongo.so",
32
+ # :sudo => true }
33
+ # end
34
+ #
35
+ class Pecl < Installer
36
+ attr_accessor :package_name, :package_version
37
+
38
+ api do
39
+ def pecl(package_name, options = {}, &block)
40
+ install Pecl.new(self, package_name, options, &block)
41
+ end
42
+ end
43
+
44
+ verify_api do
45
+ def has_pecl(package_name, options = {})
46
+ @commands = "TERM= pecl list | grep '^#{package_name}\\\\s*" + (options[:version] ? options[:version].to_s : "") + "'"
47
+ end
48
+ end
49
+
50
+ def initialize(parent, package_name, options = {}, &block) #:nodoc:
51
+ super parent, &block
52
+ @package_name = package_name
53
+ @package_version = options[:version]
54
+ @ini_file = options[:ini_file]
55
+ setup_ini if @ini_file
56
+ end
57
+
58
+ def setup_ini
59
+ @ini_file = to_ini_file_hash(@ini_file)
60
+ text = @ini_file[:content] || "extension=#{@package_name}.so"
61
+ path = @ini_file[:path] || "/etc/php5/conf.d/#{@package_name}.ini"
62
+ use_sudo = @ini_file[:sudo]===false ? false : true
63
+ post(:install) do
64
+ file(path, :content => text, :sudo => use_sudo)
65
+ end
66
+ end
67
+
68
+ def to_ini_file_hash(s)
69
+ return {:content => s} if s.is_a? String
70
+ return {} if s===true
71
+ s
72
+ end
73
+
74
+ protected
75
+ def install_commands #:nodoc:
76
+ cmd = "TERM= pecl install --alldeps #{@package_name}"
77
+ cmd << "-#{@package_version}" if @package_version
78
+ cmd
79
+ end
80
+ end
81
+ end
82
+ end
@@ -21,7 +21,7 @@ module Sprinkle
21
21
  # :RECONNECT is a symbol that the actors understand to mean to drop
22
22
  # and reestablish any SSH conncetions they have open
23
23
  def install_commands #:nodoc:
24
- :RECONNECT
24
+ Commands::Reconnect.new()
25
25
  end
26
26
 
27
27
  end
@@ -103,7 +103,7 @@ module Sprinkle
103
103
 
104
104
  multi_attributes :enable, :disable, :with, :without, :option,
105
105
  :custom_install
106
- attributes :configure_command, :build_command, :install_command, :custom_archive
106
+ attributes :configure_command, :build_command, :install_command, :custom_archive, :custom_dir
107
107
 
108
108
  def install_sequence #:nodoc:
109
109
  prepare + download + extract + configure + build + install
@@ -1,3 +1,5 @@
1
+ require 'tempfile'
2
+
1
3
  module Sprinkle
2
4
  module Installers
3
5
  # = File transfer installer
@@ -25,17 +27,34 @@ module Sprinkle
25
27
  # via this method. If you wish to disable recursive transfers, you can pass
26
28
  # :recursive => false, although it will not be obeyed when using the Vlad actor.
27
29
  #
30
+ # As an alternative to :recursive, you can use the :tarball option. When this is
31
+ # supplied, the source file(s) are first packed in a tar.gz archive, then
32
+ # transferred to a temp dir and finally unpacked at the destination. This is usually
33
+ # much faster when transferring many small files (Such as a typical rails application)
34
+ # You can optionally supply :exclude, which is an array of glob-patterns to not
35
+ # include in the tarball
36
+ #
37
+ # package :webapp do
38
+ # transfer 'app/', '/var/www/' do
39
+ # tarball :exclude => %w(.git log/*)
40
+ # end
41
+ # end
42
+ #
28
43
  # Should you need to run commands before or after the file transfer (making
29
44
  # directories or changing permissions), you can use the pre/post :install directives
30
45
  # and they will be run.
31
- #
46
+ #
32
47
  # == Rendering templates
33
48
  #
34
49
  # Rendering templates with transfer has been depreciated. Please see the file
35
50
  # installer if you want to use templates.
36
51
  class Transfer < Installer
37
52
  attr_accessor :source, :destination, :sourcepath #:nodoc:
38
-
53
+
54
+ # Include deprecated code
55
+ # Mainly, this makes it easier to see where to cut, when next major version comes along
56
+ DEPRECATED = true #:nodoc:
57
+
39
58
  api do
40
59
  def transfer(source, destination, options = {}, &block)
41
60
  options.reverse_merge!(:binding => binding())
@@ -43,92 +62,136 @@ module Sprinkle
43
62
  end
44
63
  end
45
64
 
46
- def initialize(parent, source, destination, options={}, &block) #:nodoc:
47
- @source = source
48
- @destination = destination
49
- @orig_destination = destination
50
- super parent, options, &block
51
- @binding = options[:binding]
52
- if sudo? # perform the transfer in two steps if we're using sudo
53
- final = @destination
54
- @destination = "/tmp/sprinkle_#{File.basename(@destination)}"
55
- # make sure we push the move ahead of any other post install tasks
56
- # a user may have requested
57
- post(:install).unshift ["#{sudo_cmd}mv #{@destination} #{final}"]
58
- end
65
+ def initialize(parent, source, destination, options = {}, &block) #:nodoc:
66
+ options.reverse_merge! :recursive => true
67
+
68
+ @source = source # Original source
69
+ @sourcepath = source # What the actor will transfer (may be the same as @source)
70
+ @final_destination = destination # Final destination
71
+ @destination = destination # Where the actor will place the file (May be same as @final_destination)
72
+
59
73
  owner(options[:owner]) if options[:owner]
60
74
  mode(options[:mode]) if options[:mode]
75
+ tarball(options[:tarball]) if options[:tarball]
76
+
77
+ super parent, options, &block
78
+
79
+ if DEPRECATED
80
+ @binding = options[:binding]
81
+ options[:render] = true if source_is_template?
82
+ options[:recursive] = false if options[:render]
83
+ setup_rendering if options[:render]
84
+ end
85
+ setup_tarball if tarball?
86
+ setup_sudo if sudo?
87
+ end
61
88
 
62
- options[:render]=true if source_is_template?
63
- options[:recursive]=false if options[:render]
89
+ def tarball(options = {})
90
+ @tarball = true
91
+ @exclude = options===true ? [] : options[:exclude]
64
92
  end
65
-
93
+
66
94
  def owner(owner)
67
95
  @owner = owner
68
- post :install, "#{sudo_cmd}chown #{owner} #{@orig_destination}"
96
+ post(:install, "#{sudo_cmd}chown -R #{@owner} #{@final_destination}")
69
97
  end
70
-
98
+
71
99
  def mode(mode)
72
100
  @mode = mode
73
- post :install, "#{sudo_cmd}chmod #{mode} #{@orig_destination}"
101
+ post(:install, "#{sudo_cmd}chmod -R #{@mode} #{@final_destination}")
74
102
  end
75
103
 
76
- def install_commands
77
- :TRANSFER
104
+ def tarball?
105
+ @tarball
78
106
  end
79
107
 
80
- def render_template(template, context, prefix)
81
- require 'tempfile'
82
-
83
- output = @package.template(template, context)
84
-
85
- final_tempfile = Tempfile.new(prefix.to_s)
86
- final_tempfile.print(output)
87
- final_tempfile.close
88
- final_tempfile
89
- end
90
-
91
- def render_template_file(path, context, prefix)
92
- template = source_is_template? ? path : File.read(path)
93
- tempfile = render_template(template, context, @package.name)
94
- tempfile
95
- end
96
-
97
- def source_is_template?
98
- @source.split("\n").size>1
108
+ def install_commands
109
+ Commands::Transfer.new(sourcepath, destination,
110
+ :recursive => options[:recursive])
99
111
  end
100
112
 
101
- def process(roles) #:nodoc:
102
- logger.debug "transfer: #{@source} -> #{@destination} for roles: #{roles}\n"
113
+ if DEPRECATED
114
+ def render_template(template, context, prefix)
115
+ output = @package.template(template, context)
116
+ final_tempfile = Tempfile.new(prefix.to_s)
117
+ final_tempfile.print(output)
118
+ final_tempfile.close
119
+ final_tempfile
120
+ end
103
121
 
104
- return if Sprinkle::OPTIONS[:testing]
122
+ def render_template_file(path, context, prefix)
123
+ template = source_is_template? ? path : File.read(path)
124
+ tempfile = render_template(template, context, @package.name)
125
+ tempfile
126
+ end
105
127
 
106
- if options[:render]
128
+ def source_is_template?
129
+ @source.split("\n").size > 1
130
+ end
131
+
132
+ def setup_rendering
107
133
  ActiveSupport::Deprecation.warn("transfer :render is depreciated, please use the `file` installer now.")
108
134
  ActiveSupport::Deprecation.warn("transfer :render will be removed from Sprinkle v0.8")
109
- if options[:locals]
110
- context = {}
111
- options[:locals].each_pair do |k,v|
112
- if v.respond_to?(:call)
113
- context[k] = v.call
114
- else
115
- context[k] = v
135
+ if @options[:render]
136
+ raise "Incompatible combination of options :render and :tarball" if tarball?
137
+ if @options[:locals]
138
+ context = {}
139
+ @options[:locals].each_pair do |k,v|
140
+ if v.respond_to?(:call)
141
+ context[k] = v.call
142
+ else
143
+ context[k] = v
144
+ end
116
145
  end
146
+ else
147
+ context = @binding
117
148
  end
118
- else
119
- context = @binding
149
+
150
+ @tempfile = render_template_file(@source, context, @package.name).path
151
+ @sourcepath = @tempfile
152
+ @options[:recursive] = false
120
153
  end
154
+ end
155
+ end
156
+
157
+ def setup_tarball
158
+ # tar files locally and scp to a temp location
159
+ # then untar after transfer
160
+ tar_options = @exclude.map {|glob| "--exclude \"#{glob}\" " }.join('')
161
+ @tempfile = make_tmpname
162
+ local_command = "cd '#{@source}' ; #{local_tar_bin} -zcf '#{@tempfile}' #{tar_options}."
163
+ logger.debug " --> Compressing #{@source} locally"
164
+ raise "Unable to tar #{@source}" unless system(local_command)
165
+ @sourcepath = @tempfile
166
+ @destination = "/tmp/#{File.basename(@tempfile)}"
167
+ post(:install).unshift [
168
+ "#{sudo_cmd}tar -zxf '#{@destination}' -C '#{@final_destination}'",
169
+ "#{sudo_cmd}rm '#{@destination}'"
170
+ ]
171
+ end
172
+
173
+ def setup_sudo
174
+ @destination = "/tmp/sprinkle_#{File.basename(@destination)}"
175
+ # make sure we push the move ahead of any other post install tasks
176
+ # a user may have requested
177
+ post(:install).unshift "#{sudo_cmd}mv #{@destination} #{@final_destination}"
178
+ end
121
179
 
122
- tempfile = render_template_file(@source, context, @package.name)
123
- @sourcepath = tempfile.path
124
- @options[:recursive] = false
125
- else
126
- @sourcepath = @source
180
+ protected
181
+ def local_tar_bin
182
+ @local_tar_bin ||= (`uname` =~ /Darwin/ ? "COPYFILE_DISABLE=true /usr/bin/gnutar" : "tar")
183
+ end
184
+
185
+ def post_process
186
+ return unless @tempfile
187
+ logger.debug " --> Deleting local temp file"
188
+ File.delete @tempfile
189
+ end
190
+
191
+ def make_tmpname
192
+ Dir::Tmpname.make_tmpname(['/tmp/sprinkle-', '.tar.gz'], nil)
127
193
  end
128
194
 
129
- logger.debug " --> Transferring #{sourcepath} to #{@orig_destination} for roles: #{roles}"
130
- @delivery.install(self, roles, :recursive => @options[:recursive])
131
- end
132
195
  end
133
196
  end
134
197
  end
@@ -317,7 +317,7 @@ module Sprinkle
317
317
  tree = []
318
318
  packages.each do |dep, config|
319
319
  package = PACKAGES.find_all(dep, config)
320
- raise "Package definition not found for key: #{dep}" if package.empty? and opts[:required]
320
+ raise MissingPackageError.new(dep) if package.empty? and opts[:required]
321
321
  next if package.empty? # skip missing recommended packages as they're allowed to not exist
322
322
  package = Chooser.select_package(dep, package) #if package.size>1
323
323
  package = package.instance(config)
@@ -1,7 +1,9 @@
1
+ require 'pp'
1
2
  require 'erubis'
2
3
  require 'digest/md5'
3
4
 
4
5
  module Sprinkle::Package
6
+ # For help on rendering, see the Sprinkle::Installers::FileInstaller.
5
7
  module Rendering
6
8
  extend ActiveSupport::Concern
7
9
 
@@ -9,19 +11,21 @@ module Sprinkle::Package
9
11
  self.send :include, Helpers
10
12
  end
11
13
 
14
+ # render src as ERB
12
15
  def template(src, context=binding)
13
16
  eruby = Erubis::Eruby.new(src)
14
17
  eruby.result(context)
15
18
  rescue Object => e
16
19
  raise Sprinkle::Errors::TemplateError.new(e, src, context)
17
20
  end
18
-
21
+
22
+ # read in filename and render it as ERB
19
23
  def render(filename, context=binding)
20
24
  contents=File.read(expand_filename(filename))
21
25
  template(contents, context)
22
26
  end
23
-
24
- # Helper methods can be called from inside your package and
27
+
28
+ # Helper methods can be called from inside your package and
25
29
  # verification code
26
30
  module Helpers
27
31
  # return the md5 of a string (as a hex string)
@@ -30,14 +34,49 @@ module Sprinkle::Package
30
34
  end
31
35
  end
32
36
 
33
- private
34
-
37
+ # sets the path a package should use to search for templates
38
+ def template_search_path(path)
39
+ @template_search_path = path
40
+ end
41
+
42
+ private
43
+
44
+ def search_paths(n) #:nodoc:
45
+ # if we are given an absolute path, return just that path
46
+ return [File.dirname(n)] if n.starts_with? "/"
47
+
48
+ pwd = Dir.pwd
49
+ package_dir = @template_search_path
50
+
51
+ p = []
52
+ # if ./ is used assume the path is relative to the package
53
+ if package_dir
54
+ p << File.expand_path(File.join(package_dir,"templates"))
55
+ p << File.expand_path(package_dir)
56
+ else
57
+ # otherwise search template folders relate to cwd
58
+ p << File.expand_path(File.join(pwd,"templates"))
59
+ p << File.expand_path(pwd)
60
+ end
61
+
62
+ p.uniq
63
+ end
64
+
35
65
  def expand_filename(n) #:nodoc:
36
- return n.to_s if n.to_s.starts_with? "/"
37
- ["./templates/#{n}","./templates/#{n}.erb"].each do |f|
66
+ name = File.basename(n)
67
+ paths = search_paths(n).map do |p|
68
+ [File.join(p,name), File.join(p,"#{name}.erb")]
69
+ end.flatten
70
+
71
+ paths.each do |f|
38
72
  return f if File.exist?(f)
39
73
  end
40
- raise "template file not found"
74
+
75
+ puts "RESOLVED SEARCH PATHS"
76
+ pp paths
77
+
78
+ raise "template not found: #{n}"
79
+
41
80
  end
42
81
 
43
82
  end
@@ -12,6 +12,16 @@ module Sprinkle
12
12
  end
13
13
  end
14
14
 
15
+ class MissingPackageError < StandardError #:nodoc:
16
+ def initialize(name)
17
+ @name = name
18
+ end
19
+
20
+ def to_s
21
+ "Package definition not found for key: #{@name}"
22
+ end
23
+ end
24
+
15
25
  # = Policies
16
26
  #
17
27
  # Policies define a set of packages which are required for a certain
@@ -93,7 +103,7 @@ module Sprinkle
93
103
 
94
104
  opts = args.clone.extract_options!
95
105
  package = Sprinkle::Package::PACKAGES.find_all(p, opts)
96
- raise "Package definition not found for key: #{p}" unless package
106
+ raise MissingPackageError.new(p) unless package.any?
97
107
  package = Sprinkle::Package::Chooser.select_package(p, package) if package.is_a? Array # handle virtual package selection
98
108
  # get an instance of the package and pass our config options
99
109
  package = package.instance(*args)
@@ -1,3 +1,3 @@
1
1
  module Sprinkle
2
- Version = "0.7.5"
2
+ Version = "0.7.6"
3
3
  end
@@ -7,6 +7,33 @@ describe Sprinkle::Package::Rendering, 'rendering' do
7
7
  @package = package :something do
8
8
  end
9
9
  end
10
+
11
+ describe "path expansion" do
12
+
13
+ it "should know / is root" do
14
+ dirs = @package.send :search_paths, "/test/file"
15
+ dirs.should eq ["/test"]
16
+ end
17
+
18
+ it "./ is local to where we tell it to be" do
19
+ Dir.stub(:pwd).and_return("/path/is/")
20
+ @package.template_search_path "/my/super/package/"
21
+ dirs = @package.send :search_paths, "./test/file"
22
+ dirs.should include("/my/super/package")
23
+ dirs.should include("/my/super/package/templates")
24
+ dirs.should_not include("/path/is")
25
+ dirs.should_not include("/path/is/templates")
26
+ end
27
+
28
+ it "should search pwd when amgiguous" do
29
+ Dir.stub(:pwd).and_return("/path/is/")
30
+ dirs = @package.send :search_paths, "test/file"
31
+ dirs.should include("/path/is")
32
+ dirs.should include("/path/is/templates")
33
+ dirs.size.should eq 2
34
+ end
35
+
36
+ end
10
37
 
11
38
  it "should be able to calculate md5s" do
12
39
  @package.md5("test").should == "098f6bcd4621d373cade4e832627b4f6"
@@ -7,7 +7,6 @@ describe Sprinkle::Installers::FileInstaller do
7
7
  @package = double(Sprinkle::Package, :name => 'package', :sudo? => false)
8
8
  @empty = Proc.new { }
9
9
  @delivery = double(Sprinkle::Deployment, :install => true)
10
- @source = 'source'
11
10
  @destination = 'destination'
12
11
  @contents = "hi"
13
12
  @installer = create_file_installer(@destination, :contents => @contents)
@@ -17,6 +16,12 @@ describe Sprinkle::Installers::FileInstaller do
17
16
  source do; prefix '/usr/bin'; end
18
17
  end
19
18
  end
19
+
20
+ def simplify(seq)
21
+ seq.map do |cmd|
22
+ cmd.is_a?(Sprinkle::Commands::Transfer) ? :TRANSFER : cmd
23
+ end
24
+ end
20
25
 
21
26
  def create_file_installer(dest, options={}, &block)
22
27
  i = Sprinkle::Installers::FileInstaller.new(@package, dest, options, &block)
@@ -25,14 +30,41 @@ describe Sprinkle::Installers::FileInstaller do
25
30
  end
26
31
 
27
32
  describe 'when created' do
33
+ before do
34
+ @source = "/tmp/file"
35
+ Tempfile.any_instance.stub(:path).and_return(@source)
36
+ @installer = create_file_installer(@destination, :contents => @contents)
37
+ @transfer = @installer.install_sequence.detect {|x| x.is_a? Sprinkle::Commands::Transfer }
38
+ end
39
+
28
40
  it 'should accept a source and destination to install' do
29
41
  @installer.contents.should eq @contents
30
42
  @installer.destination.should eq @destination
31
43
  end
44
+
45
+ it 'should create a transfer command' do
46
+ @transfer.source.should eq @source
47
+ @transfer.destination.should eq @destination
48
+ end
49
+
50
+ it 'should not be using recursive' do
51
+ @transfer.recursive?.should eq false
52
+ end
32
53
  end
33
54
 
34
55
  describe 'during installation' do
35
56
 
57
+ context "post process hooks" do
58
+
59
+ it "should remove its temporary file" do
60
+ @tmp = double(:print => true, :close => true, :path => "/file")
61
+ Tempfile.stub(:new).and_return(@tmp)
62
+ @installer = create_file_installer(@destination, :contents => @contents)
63
+ @tmp.should_receive(:unlink)
64
+ end
65
+
66
+ end
67
+
36
68
  context "setting mode and owner" do
37
69
  before do
38
70
  @installer = create_file_installer @destination, :content => @contents do
@@ -59,7 +91,7 @@ describe Sprinkle::Installers::FileInstaller do
59
91
  mode "744"
60
92
  owner "root"
61
93
  end
62
- @installer_commands = @installer.install_sequence
94
+ @installer_commands = simplify @installer.install_sequence
63
95
  end
64
96
 
65
97
  it "should run commands in correct order" do
@@ -78,7 +110,7 @@ describe Sprinkle::Installers::FileInstaller do
78
110
  :mode => "744", :owner => "root" do
79
111
  @options[:sudo]= true
80
112
  end
81
- @installer_commands = @installer.install_sequence
113
+ @installer_commands = simplify @installer.install_sequence
82
114
  end
83
115
 
84
116
  it "should run commands in correct order" do
@@ -99,7 +131,7 @@ describe Sprinkle::Installers::FileInstaller do
99
131
  pre :install, 'op1'
100
132
  post :install, 'op2'
101
133
  end
102
- @installer_commands = @installer.install_sequence
134
+ @installer_commands = simplify @installer.install_sequence
103
135
  @delivery = @installer.delivery
104
136
  end
105
137
 
@@ -116,7 +148,7 @@ describe Sprinkle::Installers::FileInstaller do
116
148
  pre :install, 'op1'
117
149
  post :install, 'op2'
118
150
  end
119
- @installer_commands = @installer.install_sequence
151
+ @installer_commands = simplify @installer.install_sequence
120
152
  @delivery = @installer.delivery
121
153
  end
122
154
 
@@ -132,7 +164,7 @@ describe Sprinkle::Installers::FileInstaller do
132
164
  pre :install, 'op1', 'op1-1'
133
165
  post :install, 'op2', 'op2-1'
134
166
  end
135
- @installer_commands = @installer.install_sequence
167
+ @installer_commands = simplify @installer.install_sequence
136
168
  @delivery = @installer.delivery
137
169
  end
138
170
 
@@ -0,0 +1,78 @@
1
+ require File.expand_path("../../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Sprinkle::Installers::Pecl do
4
+ before do
5
+ # @package = double(Sprinkle::Package, :name => 'spec', :class => double(Sprinkle::Package, :installer_methods => []))
6
+ @package = Package.new("test") {}
7
+ end
8
+
9
+ describe 'providing just package name' do
10
+ before do
11
+ @installer = Sprinkle::Installers::Pecl.new(@package, 'spec')
12
+ end
13
+
14
+ describe 'during installation' do
15
+ it 'should invoke the pecl installer' do
16
+ @install_commands = @installer.send :install_commands
17
+ @install_commands.should == "TERM= pecl install --alldeps spec"
18
+ end
19
+ end
20
+ end
21
+
22
+ describe 'providing explicit version' do
23
+ before do
24
+ @installer = Sprinkle::Installers::Pecl.new(@package, 'spec', :version => '1.1.1')
25
+ end
26
+
27
+ describe 'during installation' do
28
+ it 'should invoke the pecl installer' do
29
+ @install_commands = @installer.send :install_commands
30
+ @install_commands.should == "TERM= pecl install --alldeps spec-1.1.1"
31
+ end
32
+ end
33
+ end
34
+
35
+ describe 'providing ini_file option' do
36
+ describe 'during installation' do
37
+ it 'should transfer file with default arguments in post install' do
38
+ @installer = Sprinkle::Installers::Pecl.new(@package, 'spec', :ini_file => true) do
39
+ self.stub(:file) do |path,options|
40
+ path.should == "/etc/php5/conf.d/spec.ini"
41
+ options[:content].should == "extension=spec.so"
42
+ options[:sudo].should == true
43
+ "post install file transfer"
44
+ end
45
+ end
46
+ @install_sequence = @installer.install_sequence
47
+ @install_sequence.should include("TERM= pecl install --alldeps spec")
48
+ @install_sequence.should include("post install file transfer")
49
+ end
50
+
51
+ it 'should use custom path and content if provided' do
52
+ @installer = Sprinkle::Installers::Pecl.new(@package, 'spec', :ini_file => {:path => "/custom/path", :content => "hello"}) do
53
+ self.stub(:file) do |path,options|
54
+ path.should == "/custom/path"
55
+ options[:content].should == "hello"
56
+ end
57
+ end
58
+ end
59
+
60
+ it 'should use custom content if string passed' do
61
+ @installer = Sprinkle::Installers::Pecl.new(@package, 'spec', :ini_file => "hello") do
62
+ self.stub(:file) do |path,options|
63
+ options[:content].should == "hello"
64
+ end
65
+ end
66
+ end
67
+
68
+ it 'should NOT use sudo if explicitly denied' do
69
+ @installer = Sprinkle::Installers::Pecl.new(@package, 'spec', :ini_file => {:sudo => false}) do
70
+ self.stub(:file) do |path,options|
71
+ options[:sudo].should == false
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ end
@@ -201,6 +201,18 @@ describe Sprinkle::Installers::Source do
201
201
  @installer.send(:install_commands).first.should =~ /super-foo/
202
202
  end
203
203
 
204
+ end
205
+ describe 'with a custom dir definition' do
206
+ before do
207
+ @installer.options[:custom_dir] = 'super-foo'
208
+ end
209
+
210
+ it 'should install the source from the custom archive' do
211
+ @installer.send(:configure_commands).first.should =~ /super-foo/
212
+ @installer.send(:build_commands).first.should =~ /super-foo/
213
+ @installer.send(:install_commands).first.should =~ /super-foo/
214
+ end
215
+
204
216
  end
205
217
 
206
218
  describe 'with default configure, build, and install commands' do
@@ -7,7 +7,7 @@ describe Sprinkle::Installers::Transfer do
7
7
  before do
8
8
  @package = double(Sprinkle::Package, :name => 'package', :sudo? => false)
9
9
  @empty = Proc.new { }
10
- @delivery = double(Sprinkle::Deployment, :install => true)
10
+ @delivery = double(Sprinkle::Deployment, :install => true, :sudo_command => "sudo", :sudo? => false)
11
11
  @source = 'source'
12
12
  @destination = 'destination'
13
13
  @installer = create_transfer(@source, @destination)
@@ -18,6 +18,12 @@ describe Sprinkle::Installers::Transfer do
18
18
  end
19
19
  end
20
20
 
21
+ def simplify(seq)
22
+ seq.map do |cmd|
23
+ cmd.is_a?(Sprinkle::Commands::Transfer) ? :TRANSFER : cmd
24
+ end
25
+ end
26
+
21
27
  def create_transfer(source, dest, options={}, &block)
22
28
  i = Sprinkle::Installers::Transfer.new(@package, source, dest, options, &block)
23
29
  i.delivery = @delivery
@@ -29,27 +35,39 @@ describe Sprinkle::Installers::Transfer do
29
35
  @installer.source.should eq @source
30
36
  @installer.destination.should eq @destination
31
37
  end
38
+
39
+ it 'should create a transfer command with destination and source' do
40
+ transfer = @installer.install_sequence.detect {|x| x.is_a? Sprinkle::Commands::Transfer }
41
+ transfer.source.should eq @source
42
+ transfer.destination.should eq @destination
43
+ end
44
+
45
+ it 'should default to recursive true' do
46
+ transfer = @installer.install_sequence.detect {|x| x.is_a? Sprinkle::Commands::Transfer }
47
+ transfer.recursive?.should eq true
48
+ end
32
49
  end
33
50
 
34
51
  describe 'during installation' do
35
52
 
36
53
  context "setting mode and owner" do
37
- before do
54
+ before do
38
55
  @installer = create_transfer @source, @destination do
39
56
  mode "744"
40
57
  owner "root"
41
58
  end
59
+ @installer.process @roles
42
60
  @installer_commands = @installer.install_sequence
43
61
  end
44
-
62
+
45
63
  it "should include command to set owner" do
46
- @installer_commands.should include("chmod 744 #{@destination}")
64
+ @installer_commands.should include("chmod -R 744 #{@destination}")
47
65
  end
48
-
66
+
49
67
  it "should include command to set mode" do
50
- @installer_commands.should include("chown root #{@destination}")
68
+ @installer_commands.should include("chown -R root #{@destination}")
51
69
  end
52
-
70
+
53
71
  end
54
72
 
55
73
  context 'single pre/post commands' do
@@ -58,12 +76,12 @@ describe Sprinkle::Installers::Transfer do
58
76
  pre :install, 'op1'
59
77
  post :install, 'op2'
60
78
  end
61
- @installer_commands = @installer.install_sequence
79
+ @installer_commands = simplify @installer.install_sequence
62
80
  @delivery = @installer.delivery
63
81
  end
64
82
 
65
83
  it "should call the pre and post install commands around the file transfer" do
66
- @installer_commands.should eq ["op1",:TRANSFER, "op2"]
84
+ @installer_commands.should eq ["op1", :TRANSFER, "op2"]
67
85
  end
68
86
 
69
87
  # it "should call transfer with recursive defaulted to nil" do
@@ -72,21 +90,21 @@ describe Sprinkle::Installers::Transfer do
72
90
  # end
73
91
 
74
92
  end
75
-
93
+
76
94
  context 'pre/post with sudo' do
77
95
  before do
78
- @installer = create_transfer @source, @destination do
79
- @options[:sudo]= true
96
+ @delivery = double(Sprinkle::Deployment, :install => true, :sudo_command => "sudo")
97
+ @installer = create_transfer @source, @destination, :sudo => true do
80
98
  pre :install, 'op1'
81
99
  post :install, 'op2'
82
100
  end
83
- @installer_commands = @installer.install_sequence
101
+ @installer.process @roles
102
+ @installer_commands = simplify @installer.install_sequence
84
103
  @delivery = @installer.delivery
85
104
  end
86
105
 
87
106
  it "should call the pre and post install commands around the file transfer" do
88
- @installer_commands.should eq ["op1",:TRANSFER,
89
- "sudo mv /tmp/sprinkle_destination destination", "op2"]
107
+ @installer_commands.should eq ["op1", :TRANSFER, "sudo mv /tmp/sprinkle_destination destination", "op2"]
90
108
  end
91
109
  end
92
110
 
@@ -96,7 +114,7 @@ describe Sprinkle::Installers::Transfer do
96
114
  pre :install, 'op1', 'op1-1'
97
115
  post :install, 'op2', 'op2-1'
98
116
  end
99
- @installer_commands = @installer.install_sequence
117
+ @installer_commands = simplify @installer.install_sequence
100
118
  @delivery = @installer.delivery
101
119
  end
102
120
 
@@ -114,19 +132,19 @@ describe Sprinkle::Installers::Transfer do
114
132
  describe "if the :render flag is true" do
115
133
  before do
116
134
  allow(::ActiveSupport::Deprecation).to receive(:warn)
117
- @installer = create_transfer @source, @destination, :render => true
118
- @delivery = @installer.delivery
119
- @delivery.stub(:render_template_file)
120
135
  @tempfile = Tempfile.new("foo")
136
+ Sprinkle::Installers::Transfer.any_instance.
137
+ should_receive(:render_template_file).
138
+ with(@source, anything, @package.name).
139
+ and_return(@tempfile)
140
+ @installer = create_transfer @source, @destination, :render => true
121
141
  end
122
142
 
123
143
  it "should render the source file as a template to a tempfile" do
124
- @installer.should_receive(:render_template_file).with(@source, anything, @package.name).and_return(@tempfile)
125
144
  @delivery.stub(:transfer)
126
145
  end
127
146
 
128
147
  it "should call transfer with recursive set to false" do
129
- @installer.should_receive(:render_template_file).with(@source, anything, @package.name).and_return(@tempfile)
130
148
  @installer.options[:recursive].should eq false
131
149
  end
132
150
 
@@ -140,13 +158,45 @@ describe Sprinkle::Installers::Transfer do
140
158
  @installer = create_transfer @source, @destination, :recursive => false
141
159
  end
142
160
 
143
- it "should call transfer with recursive set to false" do
144
- @installer.delivery
145
- @installer.options[:recursive].should eq false
161
+ it "should created transfer command with recursive set to false" do
162
+ transfer = @installer.install_sequence.detect {|x| x.is_a? Sprinkle::Commands::Transfer }
163
+ transfer.recursive?.should eq false
146
164
  end
165
+ end
147
166
 
148
- after do
167
+ describe "if the :tarball option is set" do
168
+ it "should tar locally, then transfer and extract, finally deleting local tempfile" do
169
+ @installer = create_transfer @source, @destination, :tarball => true do
170
+ self.stub(:local_tar_bin) { "tar" }
171
+ self.stub(:make_tmpname) { "/tmp/foo.tar.gz" }
172
+ self.should_receive(:system) do |command|
173
+ command.should == "cd 'source' ; tar -zcf '/tmp/foo.tar.gz' ."
174
+ true
175
+ end
176
+ File.should_receive(:delete) do |path|
177
+ path.should == "/tmp/foo.tar.gz"
178
+ end
179
+ end
149
180
  @installer.process @roles
181
+ install_sequence = @installer.install_sequence
182
+ install_sequence.should include("tar -zxf '/tmp/foo.tar.gz' -C 'destination'")
183
+ install_sequence.should include("rm '/tmp/foo.tar.gz'")
184
+ end
185
+
186
+ describe "and the :exclude option is provided" do
187
+ it "should pass --exclude option to local tar command" do
188
+ @installer = create_transfer @source, @destination, :tarball => {:exclude => %w(.git log/*)} do
189
+ self.stub(:local_tar_bin) { "tar" }
190
+ self.stub(:make_tmpname) { "/tmp/foo.tar.gz" }
191
+ self.should_receive(:system) do |command|
192
+ command.should == "cd 'source' ; tar -zcf '/tmp/foo.tar.gz' --exclude \".git\" --exclude \"log/*\" ."
193
+ true
194
+ end
195
+ end
196
+ end
150
197
  end
198
+
151
199
  end
200
+
201
+
152
202
  end
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.5
4
+ version: 0.7.6
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-08-29 00:00:00.000000000 Z
13
+ date: 2013-09-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -189,6 +189,9 @@ files:
189
189
  - lib/sprinkle/actors/ssh.rb
190
190
  - lib/sprinkle/actors/ssh/connection_cache.rb
191
191
  - lib/sprinkle/actors/vlad.rb
192
+ - lib/sprinkle/commands/command.rb
193
+ - lib/sprinkle/commands/reconnect.rb
194
+ - lib/sprinkle/commands/transfer.rb
192
195
  - lib/sprinkle/core.rb
193
196
  - lib/sprinkle/deployment.rb
194
197
  - lib/sprinkle/errors/pretty_failure.rb
@@ -220,6 +223,7 @@ files:
220
223
  - lib/sprinkle/installers/package_installer.rb
221
224
  - lib/sprinkle/installers/pacman.rb
222
225
  - lib/sprinkle/installers/pear.rb
226
+ - lib/sprinkle/installers/pecl.rb
223
227
  - lib/sprinkle/installers/push_text.rb
224
228
  - lib/sprinkle/installers/rake.rb
225
229
  - lib/sprinkle/installers/reconnect.rb
@@ -276,6 +280,7 @@ files:
276
280
  - spec/sprinkle/installers/openbsd_pkg_spec.rb
277
281
  - spec/sprinkle/installers/opensolaris_pkg_spec.rb
278
282
  - spec/sprinkle/installers/pear_spec.rb
283
+ - spec/sprinkle/installers/pecl_spec.rb
279
284
  - spec/sprinkle/installers/push_text_spec.rb
280
285
  - spec/sprinkle/installers/rake_spec.rb
281
286
  - spec/sprinkle/installers/replace_text_spec.rb
@@ -348,6 +353,7 @@ test_files:
348
353
  - spec/sprinkle/installers/openbsd_pkg_spec.rb
349
354
  - spec/sprinkle/installers/opensolaris_pkg_spec.rb
350
355
  - spec/sprinkle/installers/pear_spec.rb
356
+ - spec/sprinkle/installers/pecl_spec.rb
351
357
  - spec/sprinkle/installers/push_text_spec.rb
352
358
  - spec/sprinkle/installers/rake_spec.rb
353
359
  - spec/sprinkle/installers/replace_text_spec.rb