deprec-core 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ deprec-core
2
+ ===========
3
+
4
+ Extracted from the deprec-gem, deprec core is a task free set of tools
5
+ to make publishing your own Capistrano/Rake task gems simpler.
6
+
7
+ To be continued...
@@ -0,0 +1,418 @@
1
+ # Copyright 2006-2008 by Mike Bailey. All rights reserved.
2
+ require 'capistrano'
3
+ require 'fileutils'
4
+
5
+ module Deprec2
6
+
7
+ # Temporarily modify ROLES if HOSTS not set
8
+ # Capistrano's default behaviour is for HOSTS to override ROLES
9
+ def for_roles(roles)
10
+ old_roles = ENV['ROLES']
11
+ ENV['ROLES'] = roles.to_s unless ENV['HOSTS']
12
+ yield
13
+ ENV['ROLES'] = old_roles.to_s unless ENV['HOSTS']
14
+ end
15
+
16
+
17
+ # Temporarily ignore ROLES and HOSTS
18
+ def ignoring_roles_and_hosts
19
+ old_roles = ENV['ROLES']
20
+ old_hosts = ENV['HOSTS']
21
+ ENV['ROLES'] = nil
22
+ ENV['HOSTS'] = nil
23
+ yield
24
+ ENV['ROLES'] = old_roles
25
+ ENV['HOSTS'] = old_hosts
26
+ end
27
+
28
+ DEPREC_TEMPLATES_BASE = File.join(File.dirname(__FILE__), 'templates')
29
+
30
+ # Render template (usually a config file)
31
+ #
32
+ # Usually we render it to a file on the local filesystem.
33
+ # This way, we keep a copy of the config file under source control.
34
+ # We can make manual changes if required and push to new hosts.
35
+ #
36
+ # If the options hash contains :path then it's written to that path.
37
+ # If it contains :remote => true, the file will instead be written to remote targets
38
+ # If options[:path] and options[:remote] are missing, it just returns the rendered
39
+ # template as a string (good for debugging).
40
+ #
41
+ # XXX I would like to get rid of :render_template_to_file
42
+ # XXX Perhaps pass an option to this function to write to remote
43
+ #
44
+ def render_template(app, options={})
45
+ template = options[:template]
46
+ path = options[:path] || nil
47
+ remote = options[:remote] || false
48
+ mode = options[:mode] || 0755
49
+ owner = options[:owner] || nil
50
+ stage = exists?(:stage) ? fetch(:stage).to_s : ''
51
+ # replace this with a check for the file
52
+ if ! template
53
+ puts "render_template() requires a value for the template!"
54
+ return false
55
+ end
56
+
57
+ # If local copies of deprec templates exist they will be used
58
+ # If you don't specify the location with the local_template_dir option
59
+ # it defaults to config/templates.
60
+ # e.g. config/templates/nginx/nginx.conf.erb
61
+ local_template = File.join(local_template_dir, app.to_s, template)
62
+ if File.exists?(local_template)
63
+ puts
64
+ puts "Using local template (#{local_template})"
65
+ template = ERB.new(IO.read(local_template), nil, '-')
66
+ else
67
+ template = ERB.new(IO.read(File.join(DEPREC_TEMPLATES_BASE, app.to_s, template)), nil, '-')
68
+ end
69
+ rendered_template = template.result(binding)
70
+
71
+ if remote
72
+ # render to remote machine
73
+ puts 'You need to specify a path to render the template to!' unless path
74
+ exit unless path
75
+ sudo "test -d #{File.dirname(path)} || #{sudo} mkdir -p #{File.dirname(path)}"
76
+ std.su_put rendered_template, path, '/tmp/', :mode => mode
77
+ sudo "chown #{owner} #{path}" if defined?(owner)
78
+ elsif path
79
+ # render to local file
80
+ full_path = File.join('config', stage, app.to_s, path)
81
+ path_dir = File.dirname(File.expand_path(full_path))
82
+ if File.exists?(full_path)
83
+ if IO.read(full_path) == rendered_template
84
+ puts "[skip] Identical file exists (#{full_path})."
85
+ return false
86
+ elsif overwrite?(full_path, rendered_template)
87
+ File.delete(full_path)
88
+ else
89
+ puts "[skip] Not overwriting #{full_path}"
90
+ return false
91
+ end
92
+ end
93
+ FileUtils.mkdir_p "#{path_dir}" if ! File.directory?(path_dir)
94
+ # added line above to make windows compatible
95
+ # system "mkdir -p #{path_dir}" if ! File.directory?(path_dir)
96
+ File.open(File.expand_path(full_path), 'w'){|f| f.write rendered_template }
97
+ puts "[done] #{full_path} written"
98
+ else
99
+ # render to string
100
+ return rendered_template
101
+ end
102
+ end
103
+
104
+ def overwrite?(full_path, rendered_template)
105
+ if defined?(overwrite_all)
106
+ if overwrite_all == true
107
+ return true
108
+ else
109
+ return false
110
+ end
111
+ end
112
+
113
+ # XXX add :always and :never later - not sure how to set persistent value from here
114
+ # response = Capistrano::CLI.ui.ask "File exists. Overwrite? ([y]es, [n]o, [a]lways, n[e]ver)" do |q|
115
+ puts
116
+ response = Capistrano::CLI.ui.ask "File exists (#{full_path}).
117
+ Overwrite? ([y]es, [n]o, [d]iff)" do |q|
118
+ q.default = 'n'
119
+ end
120
+
121
+ case response
122
+ when 'y'
123
+ return true
124
+ when 'n'
125
+ return false
126
+ when 'd'
127
+ require 'tempfile'
128
+ tf = Tempfile.new("deprec_diff")
129
+ tf.puts(rendered_template)
130
+ tf.close
131
+ puts
132
+ puts "Running diff -u current_file new_file_if_you_overwrite"
133
+ puts
134
+ system "diff -u #{full_path} #{tf.path} | less"
135
+ puts
136
+ overwrite?(full_path, rendered_template)
137
+ # XXX add :always and :never later - not sure how to set persistent value from here
138
+ # when 'a'
139
+ # set :overwrite_all, true
140
+ # when 'e'
141
+ # set :overwrite_all, false
142
+ end
143
+
144
+ end
145
+
146
+ def render_template_to_file(template_name, destination_file_name, templates_dir = DEPREC_TEMPLATES_BASE)
147
+ template_name += '.conf' if File.extname(template_name) == '' # XXX this to be removed
148
+
149
+ file = File.join(templates_dir, template_name)
150
+ buffer = render :template => File.read(file)
151
+
152
+ temporary_location = "/tmp/#{template_name}"
153
+ put buffer, temporary_location
154
+ sudo "cp #{temporary_location} #{destination_file_name}"
155
+ delete temporary_location
156
+ end
157
+
158
+ # Copy configs to server(s). Note there is no :pull task. No changes should
159
+ # be made to configs on the servers so why would you need to pull them back?
160
+ def push_configs(app, files)
161
+ app = app.to_s
162
+ stage = exists?(:stage) ? fetch(:stage).to_s : ''
163
+
164
+ files.each do |file|
165
+ full_local_path = File.join('config', stage, app, file[:path])
166
+ if File.exists?(full_local_path)
167
+ # If the file path is relative we will prepend a path to this projects
168
+ # own config directory for this service.
169
+ if file[:path][0,1] != '/'
170
+ full_remote_path = File.join(deploy_to, app, file[:path])
171
+ else
172
+ full_remote_path = file[:path]
173
+ end
174
+ sudo "test -d #{File.dirname(full_remote_path)} || #{sudo} mkdir -p #{File.dirname(full_remote_path)}"
175
+ std.su_put File.read(full_local_path), full_remote_path, '/tmp/', :mode=>file[:mode]
176
+ sudo "chown #{file[:owner]} #{full_remote_path}"
177
+ else
178
+ # Render directly to remote host.
179
+ render_template(app, file.merge(:remote => true))
180
+ end
181
+ end
182
+ end
183
+
184
+ def teardown_connections
185
+ sessions.keys.each do |server|
186
+ sessions[server].close
187
+ sessions.delete(server)
188
+ end
189
+ end
190
+
191
+ def append_to_file_if_missing(filename, value, options={})
192
+ # XXX sort out single quotes in 'value' - they'l break command!
193
+ # XXX if options[:requires_sudo] and :use_sudo then use sudo
194
+ sudo <<-END
195
+ sh -c '
196
+ grep -F "#{value}" #{filename} > /dev/null 2>&1 ||
197
+ echo "#{value}" >> #{filename}
198
+ '
199
+ END
200
+ end
201
+
202
+ # create new user account on target system
203
+ def useradd(user, options={})
204
+ options[:shell] ||= '/bin/bash' # new accounts on ubuntu 6.06.1 have been getting /bin/sh
205
+ switches = ''
206
+ switches += " --shell=#{options[:shell]} " if options[:shell]
207
+ switches += ' --create-home ' unless options[:homedir] == false
208
+ switches += " --gid #{options[:group]} " unless options[:group].nil?
209
+ invoke_command "grep '^#{user}:' /etc/passwd || #{sudo} /usr/sbin/useradd #{switches} #{user}",
210
+ :via => run_method
211
+ end
212
+
213
+ # create a new group on target system
214
+ def groupadd(group, options={})
215
+ via = options.delete(:via) || run_method
216
+ # XXX I don't like specifying the path to groupadd - need to sort out paths before long
217
+ invoke_command "grep '#{group}:' /etc/group || #{sudo} /usr/sbin/groupadd #{group}", :via => via
218
+ end
219
+
220
+ # add group to the list of groups this user belongs to
221
+ def add_user_to_group(user, group)
222
+ invoke_command "groups #{user} | grep ' #{group} ' || #{sudo} /usr/sbin/usermod -G #{group} -a #{user}",
223
+ :via => run_method
224
+ end
225
+
226
+ # create directory if it doesn't already exist
227
+ # set permissions and ownership
228
+ # XXX move mode, path and
229
+ def mkdir(path, options={})
230
+ via = options.delete(:via) || :run
231
+ # XXX need to make sudo commands wrap the whole command (sh -c ?)
232
+ # XXX removed the extra 'sudo' from after the '||' - need something else
233
+ invoke_command "test -d #{path} || #{sudo if via == :sudo} mkdir -p #{path}"
234
+ invoke_command "chmod #{sprintf("%3o",options[:mode]||0755)} #{path}", :via => via if options[:mode]
235
+ invoke_command "chown -R #{options[:owner]} #{path}", :via => via if options[:owner]
236
+ groupadd(options[:group], :via => via) if options[:group]
237
+ invoke_command "chgrp -R #{options[:group]} #{path}", :via => via if options[:group]
238
+ end
239
+
240
+ def create_src_dir
241
+ mkdir(src_dir, :mode => 0775, :group => group_src, :via => :sudo)
242
+ end
243
+
244
+ # download source pkg if we don't already have it
245
+ def download_src(src_pkg, src_dir=src_dir)
246
+ set_pkg_defaults(src_pkg)
247
+ create_src_dir
248
+ # check if file exists and if we have an MD5 hash or bytecount to compare
249
+ # against if so, compare and decide if we need to download again
250
+ if defined?(src_pkg[:md5sum])
251
+ md5_clause = " && echo '#{src_pkg[:md5sum]}' | md5sum -c - "
252
+ end
253
+ case src_pkg[:download_method]
254
+ # when getting source with git
255
+ when :git
256
+ # ensure git is installed
257
+ apt.install( {:base => %w(git-core)}, :stable) #TODO fix this to test ubuntu version <hardy might need specific git version for full git submodules support
258
+ pkg_dir = File.join(src_dir, src_pkg[:dir])
259
+ run "if [ -d #{pkg_dir} ]; then cd #{pkg_dir} && #{sudo} git checkout master && #{sudo} git pull && #{sudo} git submodule init && #{sudo} git submodule update; else #{sudo} git clone #{src_pkg[:url]} #{pkg_dir} && cd #{pkg_dir} && #{sudo} git submodule init && #{sudo} git submodule update ; fi"
260
+ # Checkout the revision wanted if defined
261
+ if src_pkg[:version]
262
+ run "cd #{pkg_dir} && git branch | grep '#{src_pkg[:version]}$' && #{sudo} git branch -D '#{src_pkg[:version]}'; exit 0"
263
+ run "cd #{pkg_dir} && #{sudo} git checkout -b #{src_pkg[:version]} #{src_pkg[:version]}"
264
+ end
265
+
266
+ # when getting source with wget
267
+ when :http
268
+ # ensure wget is installed
269
+ apt.install( {:base => %w(wget)}, :stable )
270
+ # XXX replace with invoke_command
271
+ run "cd #{src_dir} && test -f #{src_pkg[:filename]} #{md5_clause} || #{sudo} wget --quiet --timestamping #{src_pkg[:url]}"
272
+
273
+ when :deb
274
+ run "cd #{src_dir} && test -f #{src_pkg[:filename]} #{md5_clause} || #{sudo} wget --quiet --timestamping #{src_pkg[:url]}"
275
+
276
+ else
277
+ puts "DOWNLOAD SRC: Download method not recognised. src_pkg[:download_method]: #{src_pkg[:download_method]}"
278
+ end
279
+ end
280
+
281
+ # unpack src and make it writable by the group
282
+ def unpack_src(src_pkg, src_dir=src_dir)
283
+ set_pkg_defaults(src_pkg)
284
+ pkg_dir = File.join([src_dir, src_pkg[:dir]].compact)
285
+ case src_pkg[:download_method]
286
+ # when unpacking git sources - nothing to do
287
+ when :deb
288
+ puts "UNPACK SRC: nothing to do for deb installs"
289
+ when :git
290
+ puts "UNPACK SRC: nothing to do for git installs"
291
+ when :http
292
+ run "test -d #{pkg_dir}.old && #{sudo} rm -fr #{pkg_dir}.old; exit 0"
293
+ run "test -d #{pkg_dir} && #{sudo} mv #{pkg_dir} #{pkg_dir}.old; exit 0"
294
+ run "cd #{src_dir} && #{sudo} #{src_pkg[:unpack]}" if src_pkg[:unpack] != ''
295
+ run "#{sudo} chgrp -R #{group} #{pkg_dir}"
296
+ run "#{sudo} chmod -R g+w #{pkg_dir}"
297
+ else
298
+ puts "UNPACK SRC: Download method not recognised. src_pkg[:download_method]: #{src_pkg[:download_method]} "
299
+ end
300
+ end
301
+
302
+ def set_pkg_defaults(pkg)
303
+ pkg[:filename] ||= File.basename(pkg[:url])
304
+ pkg[:download_method] ||= :http
305
+ pkg[:post_install] ||= ''
306
+ case pkg[:download_method]
307
+ when :http
308
+ pkg[:dir] ||= pkg[:filename].sub(/(\.tgz|\.tar\.gz)/,'')
309
+ pkg[:unpack] ||= "tar zxf #{pkg[:filename]};"
310
+ pkg[:configure] ||= './configure ;'
311
+ pkg[:make] ||= 'make;'
312
+ pkg[:install] ||= 'make install;'
313
+ when :deb
314
+ pkg[:dir] ||= ''
315
+ pkg[:unpack] ||= ''
316
+ pkg[:configure] ||= ''
317
+ pkg[:make] ||= ''
318
+ pkg[:install] ||= "dpkg -i #{pkg[:filename]}"
319
+ end
320
+ end
321
+
322
+ # install pkg from source
323
+ def install_from_src(src_pkg, src_dir=src_dir)
324
+ install_deps(src_pkg[:deps])
325
+ set_pkg_defaults(src_pkg)
326
+ pkg_dir = File.join([src_dir, src_pkg[:dir]].compact)
327
+ unpack_src(src_pkg, src_dir)
328
+ apt.install( {:base => %w(build-essential)}, :stable )
329
+ run "cd #{pkg_dir} && #{sudo} #{src_pkg[:configure]}" if src_pkg[:configure] != ''
330
+ run "cd #{pkg_dir} && #{sudo} #{src_pkg[:make]}" if src_pkg[:make] != ''
331
+ run "cd #{pkg_dir} && #{sudo} #{src_pkg[:install]}" if src_pkg[:install] != ''
332
+ run "cd #{pkg_dir} && #{sudo} #{src_pkg[:post_install]}" if src_pkg[:post_install] != ''
333
+ end
334
+
335
+ def install_deps(packages=[])
336
+ apt.install({:base => Array(packages)}, :stable)
337
+ end
338
+
339
+ def read_database_yml
340
+ stage = exists?(:stage) ? fetch(:stage).to_s : ''
341
+ db_config = YAML.load_file(File.join('config', stage, 'database.yml'))
342
+ set :db_user, db_config[rails_env]["username"]
343
+ set :db_password, db_config[rails_env]["password"]
344
+ set :db_name, db_config[rails_env]["database"]
345
+ end
346
+
347
+
348
+ ##
349
+ # Run a command and ask for input when input_query is seen.
350
+ # Sends the response back to the server.
351
+ #
352
+ # +input_query+ is a regular expression that defaults to /^Password/.
353
+ #
354
+ # Can be used where +run+ would otherwise be used.
355
+ #
356
+ # run_with_input 'ssh-keygen ...', /^Are you sure you want to overwrite\?/
357
+
358
+ def run_with_input(shell_command, input_query=/^Password/, response=nil)
359
+ handle_command_with_input(:run, shell_command, input_query, response)
360
+ end
361
+
362
+ ##
363
+ # Run a command using sudo and ask for input when a regular expression is seen.
364
+ # Sends the response back to the server.
365
+ #
366
+ # See also +run_with_input+
367
+ #
368
+ # +input_query+ is a regular expression
369
+
370
+ def sudo_with_input(shell_command, input_query=/^Password/, response=nil)
371
+ handle_command_with_input(:sudo, shell_command, input_query, response)
372
+ end
373
+
374
+ def invoke_with_input(shell_command, input_query=/^Password/, response=nil)
375
+ handle_command_with_input(run_method, shell_command, input_query, response)
376
+ end
377
+
378
+ ##
379
+ # Run a command using sudo and continuously pipe the results back to the console.
380
+ #
381
+ # Similar to the built-in +stream+, but for privileged users.
382
+
383
+ def sudo_stream(command)
384
+ sudo(command) do |ch, stream, out|
385
+ puts out if stream == :out
386
+ if stream == :err
387
+ puts "[err : #{ch[:host]}] #{out}"
388
+ break
389
+ end
390
+ end
391
+ end
392
+
393
+ private
394
+
395
+ ##
396
+ # Does the actual capturing of the input and streaming of the output.
397
+ #
398
+ # local_run_method: run or sudo
399
+ # shell_command: The command to run
400
+ # input_query: A regular expression matching a request for input: /^Please enter your password/
401
+
402
+ def handle_command_with_input(local_run_method, shell_command, input_query, response=nil)
403
+ send(local_run_method, shell_command) do |channel, stream, data|
404
+ logger.info data, channel[:host]
405
+ if data =~ input_query
406
+ if response
407
+ channel.send_data "#{response}\n"
408
+ else
409
+ response = ::Capistrano::CLI.password_prompt "#{data}"
410
+ channel.send_data "#{response}\n"
411
+ end
412
+ end
413
+ end
414
+ end
415
+
416
+ end
417
+
418
+ Capistrano.plugin :deprec2, Deprec2
@@ -1,5 +1,5 @@
1
1
  module Deprec
2
2
  module Core
3
- VERSION = "3.1.0"
3
+ VERSION = "3.1.1"
4
4
  end
5
5
  end
@@ -0,0 +1,20 @@
1
+ # =all.rb: Load all the Capistrano Plugins in the directory.
2
+ #
3
+ # Require all other ruby files in the directory.
4
+ #
5
+ # ----
6
+ # Copyright (c) 2007 Neil Wilson, Aldur Systems Ltd
7
+ #
8
+ # Licensed under the GNU Public License v2. No warranty is provided.
9
+ # ----
10
+ # = Usage
11
+ #
12
+ # require 'vmbuilder_plugins/all'
13
+
14
+ # Splitting and joining __FILE__ deals with the current directory case
15
+ # properly
16
+ Dir[File.join( File.dirname(__FILE__), '*.rb')].each do |plugin_name|
17
+ unless plugin_name == File.join(File.dirname(__FILE__), File.basename(__FILE__))
18
+ require plugin_name
19
+ end
20
+ end
@@ -0,0 +1,93 @@
1
+ # =apt.rb: Debian 'apt' Installer library
2
+ # Capistrano plugin module to install and manage apt packages
3
+ #
4
+ # ----
5
+ # Copyright (c) 2007 Neil Wilson, Aldur Systems Ltd
6
+ #
7
+ # Licensed under the GNU Public License v2. No warranty is provided.
8
+
9
+ require 'capistrano'
10
+
11
+ # = Purpose
12
+ # Apt is a Capistrano plugin module providing a set of methods
13
+ # that invoke the *apt* package manager (as used in Debian and Ubuntu)
14
+ #
15
+ # Installs within Capistrano as the plugin _apt_.
16
+ #
17
+ # =Usage
18
+ #
19
+ # require 'vmbuilder_plugins/apt'
20
+ #
21
+ # Prefix all calls to the library with <tt>apt.</tt>
22
+ #
23
+ module Apt
24
+
25
+ # Default apt-get command - reduces any interactivity to the minimum.
26
+ APT_GET="DEBCONF_TERSE='yes' DEBIAN_PRIORITY='critical' DEBIAN_FRONTEND=noninteractive apt-get"
27
+
28
+ # Run the apt install program across the package list in 'packages'.
29
+ # Select those packages referenced by <tt>:base</tt> and the +version+
30
+ # of the distribution you want to use.
31
+ def install(packages, version, options={})
32
+ update
33
+ special_options="--allow-unauthenticated" if version != :stable
34
+ send(run_method, %{
35
+ sh -c "#{APT_GET} -qyu --force-yes #{special_options.to_s} install #{package_list(packages, version)}"
36
+ }, options)
37
+ end
38
+
39
+ # Run an apt clean
40
+ def clean(options={})
41
+ send(run_method, %{sh -c "#{APT_GET} -qy clean"}, options)
42
+ end
43
+
44
+ # Run an apt autoclean
45
+ def autoclean(options={})
46
+ send(run_method, %{sh -c "#{APT_GET} -qy autoclean"}, options)
47
+ end
48
+
49
+ # Run an apt distribution upgrade
50
+ def dist_upgrade(options={})
51
+ update
52
+ send(run_method, %{sh -c "#{APT_GET} -qy dist-upgrade"}, options)
53
+ end
54
+
55
+ # Run an apt upgrade. Use dist_upgrade instead if you want to upgrade
56
+ # the critical base packages.
57
+ def upgrade(options={})
58
+ update
59
+ send(run_method, %{sh -c "#{APT_GET} -qy upgrade"}, options)
60
+ end
61
+
62
+ # Run an apt update.
63
+ def update(options={})
64
+ send(run_method, %{sh -c "#{APT_GET} -qy update"}, options)
65
+ end
66
+
67
+ # RPM package install via alien
68
+ def rpm_install(packages, options={})
69
+ install({:base => %w(wget alien) }, :base)
70
+ send(run_method, "wget -Ncq #{packages.join(' ')}", options)
71
+ files=packages.collect { |package| File.basename(package) }
72
+ send(run_method, "alien -i #{files.join(' ')}", options)
73
+ end
74
+
75
+ # Clear the source list and package cache
76
+ def clear_cache(options={})
77
+ clean
78
+ cmd="rm -f /var/cache/apt/*.bin /var/lib/apt/lists/*_* /var/lib/apt/lists/partial/*"
79
+ send(run_method, cmd, options)
80
+ end
81
+
82
+ private
83
+
84
+ # Provides a string containing all the package names in the base
85
+ #list plus those in +version+.
86
+ def package_list(packages, version)
87
+ Array(packages[:base]).join(' ') + ' ' + Array(packages[version]).join(' ')
88
+ end
89
+
90
+ end
91
+
92
+ Capistrano.plugin :apt, Apt
93
+ # vim: nowrap sw=2 sts=2 ts=8 ff=unix ft=ruby:
@@ -0,0 +1,76 @@
1
+ # =emerge.rb: Gentoo 'emerge' Installer library
2
+ # Capistrano task library to install and manage portage packages
3
+ #
4
+ # Copyright (c) 2007 monki(Wesley Beary)
5
+ #
6
+ # inspiration: vmbuilder by Neil Wilson, Aldur Systems Ltd
7
+ #
8
+ # Licenced under the GNU Public License v2. No warranty is provided.
9
+
10
+ require 'capistrano'
11
+
12
+ # =Purpose
13
+ # emerge is a Capistrano plugin module providing a set of methods
14
+ # that invoke the portage package manage (as used in Gentoo)
15
+ #
16
+ # Installs within Capistrano as the plugin _emerge_.
17
+ #
18
+ # =Usage
19
+ #
20
+ # require 'marshall/plugins/emerge'
21
+ #
22
+ # Prefix all calls to the library with <tt>emerge.</tt>
23
+ #
24
+ module Emerge
25
+ # Default emerge command - reduce interactivity to the minimum
26
+ EMERGE="emerge -q"
27
+
28
+ # Emerge a new package or packages
29
+ def install(packages, options={})
30
+ cmd = <<-CMD
31
+ sh -c "#{EMERGE} #{packages.join(" ")}"
32
+ CMD
33
+ sudo(cmd, options)
34
+ end
35
+
36
+ # Run clean old/unused packages
37
+ def clean(options={})
38
+ cmd = <<-CMD
39
+ sh -c "#{EMERGE} -clean"
40
+ CMD
41
+ sudo(cmd, options)
42
+ end
43
+
44
+ # Upgrade installed package list
45
+ def upgrade(options={})
46
+ cmd = <<-CMD
47
+ sh -c "#{EMERGE} --sync"
48
+ CMD
49
+ sudo(cmd, options)
50
+ end
51
+
52
+ # Update portage
53
+ def update_system(options={})
54
+ cmd = <<-CMD
55
+ sh -c "#{EMERGE} portage"
56
+ CMD
57
+ sudo(cmd, options)
58
+ end
59
+
60
+ # Update all installed packages
61
+ def update(options={})
62
+ cmd = <<-CMD
63
+ sh -c "#{EMERGE} --update --deep --newuse world"
64
+ CMD
65
+ sudo(cmd, options)
66
+ end
67
+
68
+ # Boot script manipulation command
69
+ def rc_update(packages, setting)
70
+ packages.each do |service|
71
+ sudo "rc_update add #{service} #{setting}"
72
+ end
73
+ end
74
+ end
75
+
76
+ Capistrano.plugin :emerge, Emerge
@@ -0,0 +1,90 @@
1
+ # =gem.rb: Gem Installer library
2
+ # Capistrano library to install and manage Ruby Gems.
3
+ #
4
+ # ----
5
+ # Copyright (c) 2007 Neil Wilson, Aldur Systems Ltd
6
+ #
7
+ # Licensed under the GNU Public License v2. No warranty is provided.
8
+
9
+ require 'capistrano'
10
+
11
+ # = Purpose
12
+ # Gem is a Capistrano plugin module providing a set of methods
13
+ # that invoke the *gem* package manager.
14
+ #
15
+ # Installs within Capistrano as the plugin _gem_.
16
+ #
17
+ # =Usage
18
+ #
19
+ # require 'vmbuilder_plugins/gem'
20
+ #
21
+ # Prefix all calls to the library with <tt>gem.</tt>
22
+ #
23
+ module Gem
24
+
25
+ # Default install command
26
+ #
27
+ # * doesn't install documentation
28
+ # * installs all required dependencies automatically.
29
+ #
30
+ GEM_INSTALL="gem install --no-rdoc --no-ri"
31
+ GEM_UPDATE=GEM_INSTALL.sub("install", "update")
32
+
33
+ # Upgrade the *gem* system to the latest version. Runs via *sudo*
34
+ def update_system
35
+ send(run_method, "#{GEM_UPDATE} --system")
36
+ end
37
+
38
+ # Updates all the installed gems to the latest version. Runs via *sudo*.
39
+ # Don't use this command if any of the gems require a version selection.
40
+ def upgrade
41
+ send(run_method, GEM_UPDATE)
42
+ end
43
+
44
+ # Removes old versions of gems from installation area.
45
+ def cleanup
46
+ send(run_method, "gem cleanup")
47
+ end
48
+
49
+ # Installs the gems detailed in +packages+, selecting version +version+ if
50
+ # specified.
51
+ #
52
+ # +packages+ can be a single string or an array of strings.
53
+ #
54
+ def install(packages, version=nil)
55
+ send(run_method,"#{GEM_INSTALL} #{if version then '-v '+version.to_s end} #{Array(packages).join(' ')}")
56
+ end
57
+
58
+ # Auto selects a gem from a list and installs it.
59
+ #
60
+ # *gem* has no mechanism on the command line of disambiguating builds for
61
+ # different platforms, and instead asks the user. This method has the necessary
62
+ # conversation to select the +version+ relevant to +platform+ (or the one nearest
63
+ # the top of the list if you don't specify +version+).
64
+ def select(package, version=nil, platform='ruby')
65
+ selections={}
66
+ cmd="#{GEM_INSTALL} #{if version then '-v '+version.to_s end} #{package}"
67
+ send run_method, cmd do |channel, stream, data|
68
+ data.each_line do | line |
69
+ case line
70
+ when /\s(\d+).*\(#{platform}\)/
71
+ if selections[channel[:host]].nil?
72
+ selections[channel[:host]]=$1.dup+"\n"
73
+ logger.info "Selecting #$&", "#{stream} :: #{channel[:host]}"
74
+ end
75
+ when /\s\d+\./
76
+ # Discard other selections from data stream
77
+ when /^>/
78
+ channel.send_data selections[channel[:host]]
79
+ logger.debug line, "#{stream} :: #{channel[:host]}"
80
+ else
81
+ logger.info line, "#{stream} :: #{channel[:host]}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ Capistrano.plugin :gem2, Gem
90
+ # vim: nowrap sw=2 sts=2 ts=8 ff=unix ft=ruby:
@@ -0,0 +1,203 @@
1
+ # =std.rb: Capistrano Standard Methods
2
+ # Standard library of procedures and functions that you can use with Capistrano.
3
+ #
4
+ # ----
5
+ # Copyright (c) 2007 Neil Wilson, Aldur Systems Ltd
6
+ #
7
+ # Licensed under the GNU Public License v2. No warranty is provided.
8
+
9
+ require 'capistrano'
10
+
11
+ # = Purpose
12
+ # Std is a Capistrano plugin that provides a set of standard methods refactored
13
+ # out of several Capistrano task libraries.
14
+ #
15
+ # Installs within Capistrano as the plugin _std_
16
+ #
17
+ # = Usage
18
+ #
19
+ # require 'vmbuilder_plugins/std'
20
+ #
21
+ # Prefix all calls to the library with <tt>std.</tt>
22
+ module Std
23
+
24
+ begin
25
+ # Use the Mmap class if it is available
26
+ # http://moulon.inra.fr/ruby/mmap.html
27
+ require 'mmap'
28
+ MMAP=true #:nodoc:
29
+ rescue LoadError
30
+ # no MMAP class, use normal reads instead
31
+ MMAP=false #:nodoc:
32
+ end
33
+
34
+ # Copies the files specified by +file_pattern+ to +destination+
35
+ #
36
+ # Error checking is minimal - a pattern onto a single file will result in +destination+
37
+ # containing the data from the last file only.
38
+ #
39
+ # Installs via *sudo*, +options+ are as for *put*.
40
+ def fput(file_pattern, destination, options={})
41
+ logger.info file_pattern
42
+ Dir.glob(file_pattern) do |fname|
43
+ if File.readable?(fname) then
44
+ if MMAP
45
+ logger.debug "Using Memory Mapped File Upload"
46
+ fdata=Mmap.new(fname,"r", Mmap::MAP_SHARED, :advice => Mmap::MADV_SEQUENTIAL)
47
+ else
48
+ fdata=File.open(fname).read
49
+ end
50
+ su_put(fdata, destination, File.join('/tmp',File.basename(fname)), options)
51
+ else
52
+ logger.error "Unable to read file #{fname}"
53
+ end
54
+ end
55
+ end
56
+
57
+ # Upload +data+ to +temporary_area+ before installing it in
58
+ # +destination+ using sudo.
59
+ #
60
+ # +options+ are as for *put*
61
+ #
62
+ def su_put(data, destination, temporary_area='/tmp', options={})
63
+ temporary_area = File.join(temporary_area,"#{File.basename(destination)}-$CAPISTRANO:HOST$")
64
+ put(data, temporary_area, options)
65
+ send run_method, <<-CMD
66
+ sh -c "install -m#{sprintf("%3o",options[:mode]||0755)} #{temporary_area} #{destination} &&
67
+ rm -f #{temporary_area}"
68
+ CMD
69
+ end
70
+
71
+ # Copies the +file_pattern+, which is assumed to be a tar
72
+ # file of some description (gzipped or plain), and unpacks it into
73
+ # +destination+.
74
+ def unzip(file_pattern, destination, options={})
75
+ Dir.glob(file_pattern) do |fname|
76
+ if File.readable?(fname) then
77
+ target="/tmp/#{File.basename(fname)}"
78
+ if MMAP
79
+ logger.debug "Using Memory Mapped File Upload"
80
+ fdata=Mmap.new(fname,"r", Mmap::MAP_SHARED, :advice => Mmap::MADV_SEQUENTIAL)
81
+ else
82
+ fdata=File.open(fname).read
83
+ end
84
+ put(fdata, target, options)
85
+ send run_method, <<-CMD
86
+ sh -c "cd #{destination} &&
87
+ zcat -f #{target} | tar xvf - &&
88
+ rm -f #{target}"
89
+ CMD
90
+ end
91
+ end
92
+ end
93
+
94
+ # Wrap this around your task calls to catch the no servers error and
95
+ # ignore it
96
+ #
97
+ # std.ignore_no_servers_error do
98
+ # activate_mysql
99
+ # end
100
+ #
101
+ def ignore_no_servers_error (&block)
102
+ begin
103
+ yield
104
+ rescue RuntimeError => failure
105
+ if failure.message =~ /no servers matched/
106
+ logger.debug "Ignoring 'no servers matched' error in task #{current_task.name}"
107
+ else
108
+ raise
109
+ end
110
+ end
111
+ end
112
+
113
+ # Wrap this around your task to force a connection as root.
114
+ # Flushes the session cache before and after the connection.
115
+ #
116
+ # std.connect_as_root do
117
+ # install_sudo
118
+ # end
119
+ #
120
+ def connect_as_root (&block)
121
+ begin
122
+ tempuser = user
123
+ set :user, "root"
124
+ actor.sessions.delete_if { true }
125
+ yield tempuser
126
+ ensure
127
+ set :user, tempuser if tempuser
128
+ actor.sessions.delete_if { true }
129
+ end
130
+ end
131
+
132
+ #Returns a random string of alphanumeric characters of size +size+
133
+ #Useful for passwords, usernames and the like.
134
+ def random_string(size=10)
135
+ s = ""
136
+ size.times { s << (i = rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr }
137
+ s
138
+ end
139
+
140
+
141
+ # Return a relative path from the destination directory +from_str+
142
+ # to the target file/directory +to_str+. Used to create relative
143
+ # symbolic link paths.
144
+ def relative_path (from_str, to_str)
145
+ require 'pathname'
146
+ Pathname.new(to_str).relative_path_from(Pathname.new(from_str)).to_s
147
+ end
148
+
149
+ # Run a ruby command file on the servers
150
+ #
151
+ def ruby(cmd, options={}, &block)
152
+ temp_name = random_string + ".rb"
153
+ begin
154
+ put(cmd, temp_name, :mode => 0700)
155
+ send(run_method, "ruby #{temp_name}", options, &block)
156
+ ensure
157
+ delete temp_name
158
+ end
159
+ end
160
+
161
+ # Run a patchfile on the servers
162
+ # Ignores reverses and rejects.
163
+ #
164
+ def patch(patchfile, level = '0', where = '/')
165
+ temp_name = random_string
166
+ begin
167
+ fput(patchfile, temp_name, :mode => 0600)
168
+ send(run_method, %{
169
+ patch -p#{level} -tNd #{where} -r /dev/null < #{temp_name} || true
170
+ })
171
+ ensure
172
+ delete temp_name
173
+ end
174
+ end
175
+
176
+ # Deletes the given file(s) from all servers targetted by the current
177
+ # task, but runs the +delete+ command according to the current setting
178
+ # of <tt>:use_sudo</tt>.
179
+ #
180
+ # If <tt>:recursive => true</tt> is specified, it may be used to remove
181
+ # directories.
182
+ def su_delete(path, options={})
183
+ cmd = "rm -%sf #{path}" % (options[:recursive] ? "r" : "")
184
+ send(run_method, cmd, options)
185
+ end
186
+
187
+ # Render a template file and upload it to the servers
188
+ #
189
+ def put_template(template, destination, options={})
190
+ if MMAP
191
+ logger.debug "Using Memory Mapped File Upload"
192
+ fdata=Mmap.new(template,"r", Mmap::MAP_SHARED, :advice => Mmap::MADV_SEQUENTIAL)
193
+ else
194
+ fdata=File.read(template)
195
+ end
196
+ put(render(:template => fdata), destination, options)
197
+ end
198
+
199
+ end
200
+
201
+ Capistrano.plugin :std, Std
202
+ #
203
+ # vim: nowrap sw=2 sts=2 ts=8 ff=unix ft=ruby:
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: deprec-core
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 3.1.0
5
+ version: 3.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Mike Bailey
@@ -25,10 +25,17 @@ extra_rdoc_files: []
25
25
  files:
26
26
  - .gitignore
27
27
  - Gemfile
28
+ - README.md
28
29
  - Rakefile
29
30
  - deprec-core.gemspec
30
31
  - lib/deprec-core.rb
32
+ - lib/deprec-core/capistrano_extensions.rb
31
33
  - lib/deprec-core/version.rb
34
+ - lib/vmbuilder_plugins/all.rb
35
+ - lib/vmbuilder_plugins/apt.rb
36
+ - lib/vmbuilder_plugins/emerge.rb
37
+ - lib/vmbuilder_plugins/gem.rb
38
+ - lib/vmbuilder_plugins/std.rb
32
39
  homepage: ""
33
40
  licenses: []
34
41