joekhoobyar-capsaicin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Joe Khoobyar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = capsaicin
2
+
3
+ Joe Khoobyar's spicy capistrano extensions.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Joe Khoobyar. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'rake/rdoctask'
5
+ require 'rake/testtask'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |s|
10
+ s.name = "capsaicin"
11
+ s.homepage = "http://github.com/joekhoobyar/capsaicin"
12
+ s.summary = "Joe Khoobyar's spicy capistrano extensions"
13
+ s.description = %Q{Spicy capistrano extensions for various needs}
14
+
15
+ s.authors = ["Joe Khoobyar"]
16
+ s.email = "joe@ankhcraft.com"
17
+
18
+ s.add_dependency 'capistrano'
19
+ s.add_dependency 'archive-tar-minitar'
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
23
+ end
24
+
25
+ # --------- RDoc Documentation ---------
26
+ desc "Generate RDoc documentation"
27
+ Rake::RDocTask.new(:rdoc) do |rdoc|
28
+ rdoc.options << '--line-numbers' << '--inline-source' <<
29
+ '--main' << 'README' <<
30
+ '--title' << "Capsaicin" <<
31
+ '--charset' << 'utf-8'
32
+ rdoc.rdoc_dir = "doc"
33
+ rdoc.rdoc_files.include 'README*'
34
+ rdoc.rdoc_files.include('lib/**/*.rb')
35
+ end
36
+
37
+ Rake::TestTask.new do |t|
38
+ t.libs << "test"
39
+ t.libs << "lib"
40
+ end
41
+
42
+ task :default => :build
43
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
data/lib/capsaicin.rb ADDED
@@ -0,0 +1,9 @@
1
+ unless Capistrano::Configuration.respond_to?(:instance)
2
+ abort "capsaicin requires capistrano 2.0 or later"
3
+ end
4
+ require 'capistrano'
5
+
6
+ require File.join(File.dirname(__FILE__), %w(capsaicin sys))
7
+ require File.join(File.dirname(__FILE__), %w(capsaicin invocation))
8
+ require File.join(File.dirname(__FILE__), %w(capsaicin files))
9
+ require File.join(File.dirname(__FILE__), %w(capsaicin service))
@@ -0,0 +1,7 @@
1
+ module Capsaicin
2
+ module Bundle
3
+
4
+ end
5
+
6
+ Capistrano.plugin :bundle
7
+ end
@@ -0,0 +1,41 @@
1
+ module Capsaicin
2
+ module Files
3
+
4
+ COMMANDS = [ %w(mkdir mkdir_p rmdir cp cp_r rm rm_f rm_r rm_rf
5
+ chmod chmod_R chown chown_R touch),
6
+ %w(ln ln_s ln_sf mv install) ]
7
+
8
+ FILE_TESTS = [
9
+ %w(blockdev? -b),
10
+ %w(chardev? -c),
11
+ %w(directory? -d),
12
+ %w(exists? -e),
13
+ %w(file? -f),
14
+ %w(grpowned? -G),
15
+ %w(owned? -O),
16
+ %w(pipe? -p),
17
+ %w(readable? -r),
18
+ %w(setgid? -g),
19
+ %w(setuid? -u),
20
+ %w(size? -s),
21
+ %w(socket? -S),
22
+ %w(sticky? -k),
23
+ %w(symlink? -h),
24
+ %w(writable? -w),
25
+ %w(executable? -x)
26
+ ]
27
+
28
+ require File.join(File.dirname(__FILE__), %w(files local.rb))
29
+ require File.join(File.dirname(__FILE__), %w(files remote.rb))
30
+
31
+ class_eval(Local.public_instance_methods(false).map do |m|
32
+ "def #{m}(*args, &block)\n send(_via.to_s + '_files').#{m}(*args, &block)\nend"
33
+ end.join("\n"), __FILE__, __LINE__)
34
+
35
+ def _via
36
+ @config.fetch(:files_via, :remote).to_sym != :local ? :remote : :local
37
+ end
38
+ end
39
+ end
40
+
41
+ Capistrano.plugin :files, Capsaicin::Files
@@ -0,0 +1,49 @@
1
+ require 'fileutils'
2
+
3
+ module Capsaicin
4
+ module Files
5
+ module Local
6
+
7
+ include FileUtils::Verbose
8
+
9
+ public *COMMANDS.flatten
10
+ public :pwd
11
+
12
+ FILE_TESTS.each do |m,t|
13
+ class_eval <<-EODEF, __FILE__, __LINE__
14
+ def #{m}(a, options={})
15
+ logger.trace "test #{t} \#{a.gsub ' ', '\\ '}" if logger
16
+ File.#{m} a
17
+ end
18
+ EODEF
19
+ end
20
+
21
+ def tail_f(file, n=10)
22
+ unless defined? File::Tail::Logfile then gem 'file-tail'; require 'file/tail' end
23
+ File::Tail::Logfile.tail(file, :backward=>n) do |line| puts line end
24
+ rescue Interrupt
25
+ logger.trace "interrupted (Ctrl-C)" if logger
26
+ end
27
+
28
+ def upload(from, to)
29
+ cp from, to
30
+ end
31
+
32
+ def download(from, to)
33
+ cp from, to
34
+ end
35
+
36
+ def cd(dir, options={})
37
+ if block_given?
38
+ dir, dir2 = pwd, dir
39
+ cd dir2
40
+ yield
41
+ end
42
+ cd dir
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+
49
+ Capistrano.plugin :local_files, Capsaicin::Files::Local
@@ -0,0 +1,109 @@
1
+ require 'fileutils'
2
+
3
+ module Capsaicin
4
+ module Files
5
+ module Remote
6
+
7
+ COMMANDS.each_with_index do |l,n|
8
+ l.each do |m|
9
+ k, f = m.split('_')
10
+ f = ' -' + f if f
11
+ class_eval <<-EODEF, __FILE__, __LINE__
12
+ def #{m}(*args)
13
+ options = args.pop if Hash === args.last
14
+ _r '#{k}#{f}', args#{', ' + (n+1).to_s if n > 0}
15
+ end
16
+ EODEF
17
+ end
18
+ end
19
+
20
+ FILE_TESTS.each do |m,t|
21
+ class_eval <<-EODEF
22
+ def #{m}(a, options={})
23
+ _t "test #{t}", a
24
+ end
25
+ EODEF
26
+ end
27
+
28
+ def tail_f(file, n=10)
29
+ cmd = "tail -n #{n} -f #{_q file}"
30
+ _via == :system ? local_run(cmd) : stream(cmd, :via => _via)
31
+ rescue Interrupt
32
+ logger.trace "interrupted (Ctrl-C)" if logger
33
+ end
34
+
35
+ def upload(*args)
36
+ _via == :system ? cp(*args) : @config.upload(*args)
37
+ end
38
+
39
+ def download(*args)
40
+ _via == :system ? cp(*args) : @config.download(*args)
41
+ end
42
+
43
+ def cd(dir, options={})
44
+ if block_given?
45
+ dir, dir2 = pwd, dir
46
+ _r 'cd', dir2
47
+ yield
48
+ end
49
+ _r 'cd', dir
50
+ end
51
+
52
+ def pwd
53
+ capture('pwd', :via => _via)
54
+ end
55
+
56
+ private
57
+
58
+ def _t(cmd, args=nil, min=nil)
59
+ cmd = _a cmd, args, min
60
+ if _via == :system then
61
+ local_run(cmd)
62
+ else
63
+ capture("#{cmd}; echo $?", :via => _via).strip == '0'
64
+ end
65
+ end
66
+
67
+ def _r(cmd, args=nil, min=nil)
68
+ cmd = _a cmd, args, min
69
+ if _via != :system then
70
+ invoke_command cmd, :via => _via
71
+ else
72
+ local_run cmd
73
+ end
74
+ end
75
+
76
+ def _a(cmd, args=nil, min=nil)
77
+ case args
78
+ when NilClass
79
+ raise ArgumentError unless min.nil? or min.zero?
80
+ when Array
81
+ args = args.flatten
82
+ raise ArgumentError if (min || 1) > args.length
83
+ cmd = "#{cmd} #{_q(*args)}" if args.any?
84
+ else
85
+ raise ArgumentError if min and min < 1
86
+ cmd = "#{cmd} #{_q args}"
87
+ end
88
+ end
89
+
90
+ def _q(*list)
91
+ list.map { |l| "'#{l.gsub("'", "\\'")}'" }.join ' '
92
+ end
93
+
94
+ def _via
95
+ case (v = @config.fetch(:files_via, nil))
96
+ when :local
97
+ :system
98
+ when :remote, NilClass
99
+ @config.fetch(:run_method, nil)
100
+ else
101
+ v
102
+ end
103
+ end
104
+
105
+ end
106
+ end
107
+ end
108
+
109
+ Capistrano.plugin :remote_files, Capsaicin::Files::Remote
@@ -0,0 +1,33 @@
1
+ module Capsaicin
2
+
3
+ module Invocation
4
+ def local_run(*args, &block)
5
+ args.pop if Hash===args.last
6
+ args = args.first
7
+ logger.debug "executing locally: #{args}"
8
+ system args
9
+ end
10
+
11
+ def sudo_as(*args, &block)
12
+ options = Hash===args.last ? args.pop.dup : {}
13
+ options[:as] = fetch(:runner, nil)
14
+ sudo *args.push(options), &block
15
+ end
16
+
17
+ def sudo_su(*args, &block)
18
+ options = Hash===args.last ? args.pop.dup : {}
19
+ args[0] = "su #{fetch(:runner, nil)} -c '#{args[0]}'"
20
+ sudo *args.push(options), &block
21
+ end
22
+
23
+ def sudo_su_to(*args, &block)
24
+ options = Hash===args.last ? args.pop.dup : {}
25
+ options[:shell] = false
26
+ cmd = args[0].gsub(/[$\\`"]/) { |m| "\\#{m}" }
27
+ args[0] = "echo \"#{cmd}\" | #{sudo} su - #{fetch(:runner, nil)}"
28
+ run *args.push(options), &block
29
+ end
30
+ end
31
+
32
+ Capistrano::Configuration.send :include, Invocation
33
+ end
@@ -0,0 +1,21 @@
1
+ module Capsaicin
2
+
3
+ module Service
4
+
5
+ SVC_ACTION_CAPTIONS = Hash.new do |h,k|
6
+ h[k] = "#{k.to_s.capitalize} Service"
7
+ end.update :status => 'Check Status',
8
+ :check => 'Check Config',
9
+ :summary => 'Status Summary'
10
+
11
+ %w(lsb crm windows command).each do |k|
12
+ require File.join(File.dirname(__FILE__), 'service', k+'.rb')
13
+ end
14
+
15
+ include LSB, CRM, Windows, Command
16
+
17
+ end
18
+
19
+ end
20
+
21
+ Capistrano.plugin :service, Capsaicin::Service
@@ -0,0 +1,44 @@
1
+ module Capsaicin
2
+ module Service
3
+ module Command
4
+
5
+ # Check for the existance of a generic Windows NT service.
6
+ def command?(start, stop)
7
+ files.executable? start and files.executable? stop
8
+ end
9
+
10
+ # Defines a recipe to control a generic Windows NT service.
11
+ #
12
+ def command(id,start,stop,*args)
13
+ options = Hash===args.last ? args.pop : {}
14
+
15
+ svc_name = id.to_s
16
+ svc_desc = next_description(:reset) || (svc_name.capitalize unless options.delete(:hide))
17
+ extras = args.pop if Array === args.last
18
+ via = options.delete(:via)
19
+
20
+ namespace id do
21
+
22
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:start]}" if svc_desc
23
+ task :start, options do
24
+ send(via || fetch(:run_method, :local_run), start)
25
+ end
26
+
27
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:stop]}" if svc_desc
28
+ task :stop, options do
29
+ send(via || fetch(:run_method, :local_run), stop)
30
+ end
31
+
32
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:restart]}" if svc_desc
33
+ task :restart, options do
34
+ stop
35
+ start
36
+ end
37
+
38
+ instance_eval { yield } if block_given?
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,84 @@
1
+ module Capsaicin
2
+ module Service
3
+ module CRM
4
+
5
+ DEFAULT_ACTIONS = [ [ :status, '-W' ],
6
+ [ :summary, "-x | awk '/^raw xml:/ { exit }; { print }'" ],
7
+ [ :start, "--meta -d 'target_role'" ],
8
+ [ :stop, "--meta -p 'target_role' -v 'stopped'" ] ]
9
+
10
+ OCF_DEFAULT_ACTIONS = [ [ :validate, '-c -C' ],
11
+ [ :monitor, '-c -m' ] ]
12
+
13
+ # Defines a recipe to control a cluster-managed service, using heartbeat or pacemaker.
14
+ #
15
+ def crm(id,*args)
16
+ options = Hash===args.last ? args.pop : {}
17
+
18
+ svc_name = id.to_s
19
+ svc_desc = next_description(:reset) || (svc_name.capitalize unless options.delete(:hide))
20
+ svc_actions = DEFAULT_ACTIONS
21
+ svc_actions += args.pop if Array === args.last
22
+
23
+ namespace id do
24
+
25
+ case args.first
26
+ when String; id = args.shift.intern
27
+ when Symbol; id = args.shift
28
+ end
29
+ svc_cmd = "/usr/sbin/crm_resource -r #{id.to_s.split(':').last}"
30
+
31
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:status]}" if svc_desc
32
+ task :default, options do
33
+ sudo "#{svc_cmd} -W"
34
+ end
35
+
36
+ svc_actions.each do |svc_action,svc_args|
37
+ svc_action = svc_action.intern unless Symbol===svc_action
38
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[svc_action]}" if svc_desc
39
+ task svc_action, options do
40
+ sudo "#{svc_cmd} #{svc_args}"
41
+ end
42
+ end
43
+
44
+ instance_eval { yield } if block_given?
45
+ end
46
+ end
47
+
48
+ # Defines a recipe providing additional controls for a cluster-managed service,
49
+ # using the ocf_resource tool which interoperates with heartbeat or pacemaker.
50
+ #
51
+ # For more information about ocf_resource and other add-ons for heartbeat/pacemaker,
52
+ # see http://github.com/joekhoobyar/ha-tools
53
+ #
54
+ def crm_ocf(id,*args)
55
+ options = Hash===args.last ? args.pop : {}
56
+
57
+ svc_name = id.to_s
58
+ svc_desc = next_description(:reset) || (svc_name.capitalize unless options.delete(:hide))
59
+ svc_actions = DEFAULT_ACTIONS
60
+ svc_actions += args.pop if Array === args.last
61
+
62
+ namespace id do
63
+
64
+ case args.first
65
+ when String; id = args.shift.intern
66
+ when Symbol; id = args.shift
67
+ end
68
+ svc_cmd = "ocf_resource -g #{id.to_s.split(':').last}"
69
+
70
+ svc_actions.each do |svc_action,svc_args|
71
+ svc_action = svc_action.intern if String === svc_action
72
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[svc_action]}" if svc_desc
73
+ task svc_action, options do
74
+ sudo "#{svc_cmd} #{svc_args}"
75
+ end
76
+ end
77
+
78
+ instance_eval { yield } if block_given?
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
@@ -0,0 +1,47 @@
1
+ module Capsaicin
2
+ module Service
3
+ module LSB
4
+
5
+ DEFAULT_ACTIONS = %w(status start stop restart)
6
+
7
+ # Check for the existance of a generic Windows NT service.
8
+ def lsb?(id)
9
+ files.exists? "/etc/init.d/#{id.to_s.split(':').last}"
10
+ end
11
+
12
+ # Defines a recipe to control a generic LSB service.
13
+ #
14
+ def lsb(id,*args)
15
+ options = Hash===args.last ? args.pop : {}
16
+
17
+ svc_name = id.to_s
18
+ svc_desc = next_description(:reset) || (svc_name.capitalize unless options.delete(:hide))
19
+ svc_actions = DEFAULT_ACTIONS
20
+ svc_actions += args.pop if Array === args.last
21
+
22
+ namespace id do
23
+ case args.first
24
+ when String; id = args.shift.intern
25
+ when Symbol; id = args.shift
26
+ end
27
+ svc_cmd = "/etc/init.d/#{id.to_s.split(':').last}"
28
+
29
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:status]}" if svc_desc
30
+ task :default, options do
31
+ sudo "#{svc_cmd} status"
32
+ end
33
+
34
+ svc_actions.each do |svc_action|
35
+ svc_action = svc_action.intern if String === svc_action
36
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[svc_action]}" if svc_desc
37
+ task svc_action, options do
38
+ sudo "#{svc_cmd} #{svc_action}"
39
+ end
40
+ end
41
+
42
+ instance_eval { yield } if block_given?
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,62 @@
1
+ module Capsaicin
2
+ module Service
3
+ module Windows
4
+
5
+ DEFAULT_ACTIONS = [:start, :stop]
6
+
7
+ # Check for the existance of a generic Windows NT service.
8
+ def windows?(id, verbose=false)
9
+ logger.trace "executing locally: sc query \"#{id}\"" if logger and verbose
10
+ $1.to_i if `sc query "#{id}"` =~ /STATE +: +([0-9])+ +([^ ]+)/
11
+ ensure
12
+ logger.trace " service status => #{$2} (#{$1})" if logger and verbose
13
+ end
14
+
15
+ # Defines a recipe to control a generic Windows NT service.
16
+ #
17
+ def windows(id,*args)
18
+ options = Hash===args.last ? args.pop : {}
19
+
20
+ svc_name = id.to_s
21
+ svc_desc = next_description(:reset) || (svc_name.capitalize unless options.delete(:hide))
22
+ svc_actions = DEFAULT_ACTIONS
23
+ svc_actions += args.pop if Array === args.last
24
+
25
+ namespace id do
26
+ case args.first
27
+ when String; id = args.shift.intern
28
+ when Symbol; id = args.shift
29
+ end
30
+
31
+ [:default, :status].each do |k|
32
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:status]}" if svc_desc
33
+ task k, options do
34
+ service.windows? id, true or
35
+ abort "Failed to get service status for #{svc_name}"
36
+ end
37
+ end
38
+
39
+ DEFAULT_ACTIONS.each do |svc_action|
40
+ svc_action = svc_action.intern if String === svc_action
41
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[svc_action]}" if svc_desc
42
+ task svc_action, options do
43
+ local_run "net #{svc_action} \"#{id}\""
44
+ end
45
+ end
46
+
47
+ desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:restart]}" if svc_desc
48
+ task :restart, options do
49
+ case service.windows?(id)
50
+ when 4, 2; stop
51
+ when NilClass; abort "Failed to get service status for #{svc_name}"
52
+ end
53
+ start
54
+ end
55
+
56
+ instance_eval { yield } if block_given?
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,11 @@
1
+ module Capsaicin
2
+ module LocalSys
3
+
4
+ def windows?
5
+ @windows ||= !! (RUBY_PLATFORM =~ /cygwin|mingw|win32|mswin|windows/)
6
+ end
7
+
8
+ end
9
+
10
+ Capistrano.plugin :local_sys, LocalSys
11
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: joekhoobyar-capsaicin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joe Khoobyar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-30 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: capistrano
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: archive-tar-minitar
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: Spicy capistrano extensions for various needs
36
+ email: joe@ankhcraft.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - LICENSE
46
+ - README.rdoc
47
+ - Rakefile
48
+ - VERSION.yml
49
+ - lib/capsaicin.rb
50
+ - lib/capsaicin/bundle.rb
51
+ - lib/capsaicin/files.rb
52
+ - lib/capsaicin/files/local.rb
53
+ - lib/capsaicin/files/remote.rb
54
+ - lib/capsaicin/invocation.rb
55
+ - lib/capsaicin/service.rb
56
+ - lib/capsaicin/service/command.rb
57
+ - lib/capsaicin/service/crm.rb
58
+ - lib/capsaicin/service/lsb.rb
59
+ - lib/capsaicin/service/windows.rb
60
+ - lib/capsaicin/sys.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/joekhoobyar/capsaicin
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --charset=UTF-8
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.2.0
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Joe Khoobyar's spicy capistrano extensions
87
+ test_files: []
88
+