capsaicin 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ begin
15
15
  s.email = "joe@ankhcraft.com"
16
16
  s.rubyforge_project = "capsaicin"
17
17
 
18
- s.add_dependency 'capistrano', ['>= 2.0']
18
+ s.add_dependency 'capistrano', ['>= 2.5']
19
19
  s.add_dependency 'archive-tar-minitar', ['>= 0.5']
20
20
  end
21
21
  rescue LoadError
@@ -26,7 +26,6 @@ require 'rake/testtask'
26
26
  Rake::TestTask.new(:test) do |test|
27
27
  test.libs << 'test'
28
28
  test.pattern = 'test/**/*_test.rb'
29
- test.verbose = true
30
29
  end
31
30
 
32
31
  begin
@@ -34,7 +33,6 @@ begin
34
33
  Rcov::RcovTask.new do |test|
35
34
  test.libs << 'test'
36
35
  test.pattern = 'test/**/*_test.rb'
37
- test.verbose = true
38
36
  end
39
37
  rescue LoadError
40
38
  task :rcov do
@@ -2,4 +2,4 @@
2
2
  :major: 0
3
3
  :minor: 1
4
4
  :build:
5
- :patch: 9
5
+ :patch: 10
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{capsaicin}
8
- s.version = "0.1.9"
8
+ s.version = "0.1.10"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Joe Khoobyar"]
12
- s.date = %q{2010-06-15}
12
+ s.date = %q{2010-06-16}
13
13
  s.description = %q{Spicy capistrano extensions for various needs}
14
14
  s.email = %q{joe@ankhcraft.com}
15
15
  s.extra_rdoc_files = [
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
39
39
  "lib/capsaicin/sys.rb",
40
40
  "lib/capsaicin/ui.rb",
41
41
  "test/capsaicin/files/local_test.rb",
42
+ "test/capsaicin/invocation_test.rb",
42
43
  "test/helper.rb"
43
44
  ]
44
45
  s.homepage = %q{http://github.com/joekhoobyar/capsaicin}
@@ -49,6 +50,7 @@ Gem::Specification.new do |s|
49
50
  s.summary = %q{Joe Khoobyar's spicy capistrano extensions}
50
51
  s.test_files = [
51
52
  "test/capsaicin/files/local_test.rb",
53
+ "test/capsaicin/invocation_test.rb",
52
54
  "test/helper.rb"
53
55
  ]
54
56
 
@@ -57,14 +59,14 @@ Gem::Specification.new do |s|
57
59
  s.specification_version = 3
58
60
 
59
61
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
60
- s.add_runtime_dependency(%q<capistrano>, [">= 2.0"])
62
+ s.add_runtime_dependency(%q<capistrano>, [">= 2.5"])
61
63
  s.add_runtime_dependency(%q<archive-tar-minitar>, [">= 0.5"])
62
64
  else
63
- s.add_dependency(%q<capistrano>, [">= 2.0"])
65
+ s.add_dependency(%q<capistrano>, [">= 2.5"])
64
66
  s.add_dependency(%q<archive-tar-minitar>, [">= 0.5"])
65
67
  end
66
68
  else
67
- s.add_dependency(%q<capistrano>, [">= 2.0"])
69
+ s.add_dependency(%q<capistrano>, [">= 2.5"])
68
70
  s.add_dependency(%q<archive-tar-minitar>, [">= 0.5"])
69
71
  end
70
72
  end
@@ -28,9 +28,6 @@ module Capistrano # :nodoc:
28
28
  FileUtils.rm_rf destination rescue nil
29
29
  end
30
30
 
31
- def check! # :nodoc:
32
- end
33
-
34
31
  private
35
32
 
36
33
  def local_copy_dir # :nodoc:
@@ -17,6 +17,14 @@ module Capsaicin
17
17
  end
18
18
  end
19
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
+
20
28
  def chmod(mode, list, options={})
21
29
  _r 'chmod', Array(list).unshift(mode.to_s(8))
22
30
  end
@@ -36,14 +44,6 @@ module Capsaicin
36
44
  _r 'install', src.push(dest)
37
45
  end
38
46
 
39
- FILE_TESTS.each do |m,t|
40
- class_eval <<-EODEF
41
- def #{m}(a, options={})
42
- _t "test #{t}", a
43
- end
44
- EODEF
45
- end
46
-
47
47
  def tail_f(file, n=10)
48
48
  cmd = "tail -n #{n} -f #{_q file}"
49
49
  case v = _via
@@ -56,6 +56,15 @@ module Capsaicin
56
56
  logger.trace "interrupted (Ctrl-C)" if logger
57
57
  end
58
58
 
59
+ def put(data, path, options={})
60
+ case _via
61
+ when :system, :local_run
62
+ FileUtils::Verbose.copy_stream StringIO.new(from), to
63
+ else
64
+ upload StringIO.new(data), path, options
65
+ end
66
+ end
67
+
59
68
  def upload(from, to, options={}, &block)
60
69
  case _via
61
70
  when :system, :local_run
@@ -70,11 +79,20 @@ module Capsaicin
70
79
  to2, to = to, "/tmp/#{tof}-#{Time.now.utc.to_i}"
71
80
  end
72
81
  end
82
+ options = options.dup
83
+ mode = options.delete(:mode)
73
84
  @config.upload(from, to, options, &block)
74
85
  if to2
75
- run "chmod 0644 #{to}"
76
- cp to, to2
77
- run "rm -f #{to}"
86
+ begin
87
+ run "chmod 0644 #{to}", :via=>:run
88
+ cp to, to2
89
+ if mode
90
+ mode = mode.is_a?(Numeric) ? '0'+mode.to_s(8) : mode.to_s
91
+ run "chmod #{mode} #{to2}"
92
+ end
93
+ ensure
94
+ run "rm -f #{to}", :via=>:run
95
+ end
78
96
  end
79
97
  end
80
98
  end
@@ -88,28 +106,6 @@ module Capsaicin
88
106
  end
89
107
  end
90
108
 
91
- def put(data, path, options={})
92
- case _via
93
- when :system, :local_run
94
- FileUtils::Verbose.copy_stream StringIO.new(from), to
95
- else
96
- if _via.to_s[0,4] == 'sudo'
97
- if path[-1]==?/ || path[-1]==?\\ || directory?(path)
98
- abort "Target path is a directory!"
99
- else
100
- pathf = File.basename path
101
- path2, path = path, "/tmp/#{pathf}-#{Time.now.utc.to_i}"
102
- end
103
- end
104
- @config.put(data, path, options)
105
- if path2
106
- run "chmod 0644 #{path}"
107
- cp path, path2
108
- run "rm -f #{path}"
109
- end
110
- end
111
- end
112
-
113
109
  def cd(dir, options={})
114
110
  if block_given?
115
111
  dir, dir2 = pwd, dir
@@ -1,28 +1,62 @@
1
1
  module Capsaicin
2
2
 
3
3
  module Invocation
4
-
4
+
5
+ def self.included(base)
6
+ [:run, :sudo].each do |k|
7
+ base.send :alias_method, :"#{k}_without_override", k
8
+ base.send :alias_method, k, :"#{k}_with_override"
9
+ end
10
+ end
11
+
12
+ # Allows overriding the default behavior of +run+ by setting
13
+ # :override_run_method and (optionally) :override_runner
14
+ def run_with_override(cmd, options={}, &block)
15
+ via = options[:via] || fetch(:override_run_method, :run)
16
+ if cmd.include?(sudo) or :run == via
17
+ run_without_override cmd, options, &block
18
+ else
19
+ options = options.dup
20
+ as = fetch(:override_runner, nil) and options[:as] ||= as
21
+ send via, cmd, options, &block
22
+ end
23
+ end
24
+
25
+ # Allows overriding the default behavior of +sudo+ by setting
26
+ # :override_sudo_method and (optionally) :override_sudo_runner
27
+ def sudo_with_override(*args, &block)
28
+ options = Hash===args.last ? args.pop.dup : {}
29
+ as = fetch(:override_sudo_runner, nil) and options[:as] ||= as
30
+ args << options unless options.empty?
31
+ if :sudo == (via = fetch(:override_sudo_method, :sudo))
32
+ options[:via] = :run
33
+ sudo_without_override *args, &block
34
+ else
35
+ send via, *args, &block
36
+ end
37
+ end
38
+
5
39
  # Automatically uses the :run_method variable to run things.
6
40
  # Equivalent to +invoke_command *args, :via=>fetch(:run_method, :run)+
7
41
  def vrun(*args, &block)
8
- options = Hash===args.last ? args.pop.dup : {}
9
- options[:via] = fetch(:run_method, :run)
42
+ options = Hash===args.last ? args.pop.dup : {}
43
+ options[:via] ||= fetch(:run_method, :run)
10
44
  invoke_command *args.push(options), &block
11
45
  end
12
46
 
13
47
  # Automatically uses the :run_method variable to run things.
14
48
  # Equivalent to +capture *args, :via=>fetch(:run_method, :run)+
15
49
  def vcapture(*args, &block)
16
- options = Hash===args.last ? args.pop.dup : {}
17
- options[:via] = fetch(:run_method, :run)
50
+ options = Hash===args.last ? args.pop.dup : {}
51
+ options[:via] ||= fetch(:run_method, :run)
18
52
  capture *args.push(options), &block
19
53
  end
20
54
 
21
55
  # Automatically uses the :run_method variable to run things.
22
56
  # Equivalent to +stream *args, :via=>fetch(:run_method, :run)+
23
57
  def vstream(*args, &block)
24
- options = Hash===args.last ? args.pop.dup : {}
25
- options[:via] = fetch(:run_method, :run)
58
+ options = Hash===args.last ? args.pop.dup : {}
59
+ options[:via] ||= fetch(:run_method, :run)
26
60
  stream *args.push(options), &block
27
61
  end
28
62
 
@@ -46,25 +80,29 @@ module Capsaicin
46
80
  # Always uses :runner to sudo as someone.
47
81
  # Equivalent to: sudo "command", :as => fetch(:runner,nil)
48
82
  def sudo_as(*args, &block)
49
- options = Hash===args.last ? args.pop.dup : {}
50
- options[:as] = fetch(:runner, nil)
51
- sudo *args.push(options), &block
83
+ options = Hash===args.last ? args.pop.dup : {}
84
+ options[:as] ||= fetch(:runner, nil)
85
+ sudo_without_override *args.push(options), &block
52
86
  end
53
87
 
54
- # Extremely helpful if you only have permission to: sudo su SOMEUSER -c "command"
88
+ # Extremely helpful if you only have permission to: sudo su SOMEUSER -c 'command'
55
89
  def sudo_su(*args, &block)
56
- options = Hash===args.last ? args.pop.dup : {}
57
- args[0] = "su #{fetch(:runner, nil)} -c '#{args[0]}'"
58
- sudo *args.push(options), &block
90
+ options = Hash===args.last ? args.pop.dup : {}
91
+ options[:as] ||= fetch(:runner, nil)
92
+ return sudo_as(options, &block) if args.empty? # compatibility with capistrano's +sudo+
93
+ args[0] = "su #{options.delete(:as)} -c '#{args[0].gsub("'","'\"'\"'")}'"
94
+ sudo_without_override *args.push(options), &block
59
95
  end
60
96
 
61
97
  # Extremely helpful if you only have permission to: sudo su - SOMEUSER
62
98
  def sudo_su_to(*args, &block)
63
- options = Hash===args.last ? args.pop.dup : {}
99
+ options = Hash===args.last ? args.pop.dup : {}
100
+ options[:as] ||= fetch(:runner, nil)
101
+ return sudo_as(options, &block) if args.empty? # compatibility with capistrano's +sudo+
64
102
  options[:shell] = false
65
- cmd = args[0].gsub(/[$\\`"]/) { |m| "\\#{m}" }
66
- args[0] = "echo \"#{cmd}\" | #{sudo} su - #{fetch(:runner, nil)}"
67
- run *args.push(options), &block
103
+ cmd = args[0].gsub(/[$\\`"]/) { |m| "\\#{m}" }
104
+ args[0] = "echo \"#{cmd}\" | #{sudo_without_override} su - #{options.delete(:as)}"
105
+ run_without_override *args.push(options), &block
68
106
  end
69
107
  end
70
108
  end
@@ -2,12 +2,12 @@ module Capsaicin
2
2
  module Service
3
3
  module Command
4
4
 
5
- # Check for the existance of a generic Windows NT service.
5
+ # Check for the existance of a command-based service.
6
6
  def command?(start, stop)
7
7
  files.executable? start and files.executable? stop
8
8
  end
9
9
 
10
- # Defines a recipe to control a generic Windows NT service.
10
+ # Defines a recipe to control a command-based service.
11
11
  #
12
12
  def command(id,start,stop,*args)
13
13
  options = Hash===args.last ? args.pop : {}
@@ -21,12 +21,12 @@ module Capsaicin
21
21
 
22
22
  desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:start]}" if svc_desc
23
23
  task :start, options do
24
- send(via || fetch(:run_method, :local_run), start)
24
+ send(via || fetch(:run_method, :run), start)
25
25
  end
26
26
 
27
27
  desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[:stop]}" if svc_desc
28
28
  task :stop, options do
29
- send(via || fetch(:run_method, :local_run), stop)
29
+ send(via || fetch(:run_method, :run), stop)
30
30
  end
31
31
 
32
32
  unless extras.key? :restart
@@ -40,7 +40,7 @@ module Capsaicin
40
40
  extras.each do |k,cmd|
41
41
  desc "#{svc_desc}: #{SVC_ACTION_CAPTIONS[k]}" if svc_desc
42
42
  task k, options do
43
- send(via || fetch(:run_method, :local_run), cmd)
43
+ send(via || fetch(:run_method, :run), cmd)
44
44
  end
45
45
  end
46
46
 
@@ -0,0 +1,112 @@
1
+ require 'helper'
2
+ require 'tmpdir'
3
+ require 'capsaicin/invocation'
4
+
5
+ class Capsaicin::InvocationTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @ext = CapistranoMock.new
9
+ class << @ext
10
+ include Capsaicin::Invocation
11
+ end
12
+ end
13
+
14
+ def teardown
15
+ end
16
+
17
+ def test_vrun
18
+ check_run_methods :vrun, :invoke_command
19
+ end
20
+
21
+ def test_vcapture
22
+ check_run_methods :vcapture, :capture
23
+ end
24
+
25
+ def test_vstream
26
+ check_run_methods :vstream, :stream
27
+ end
28
+
29
+ def test_sudo_as
30
+ check_as_methods :sudo_as, :sudo
31
+ end
32
+
33
+ def test_sudo_su
34
+ check_as_methods(:sudo_su, :sudo) {|c,as| ["su #{as} -c '#{c}'", {}] }
35
+ end
36
+
37
+ def test_sudo_su_escapes_single_quotes
38
+ check_as_methods(:sudo_su, :sudo,"echo 'abc'") do |c,as|
39
+ ["su #{as} -c 'echo '\"'\"'abc'\"'\"''", {}]
40
+ end
41
+ end
42
+
43
+ def test_sudo_su_to
44
+ check_as_methods(:sudo_su_to, :run) do |c,as|
45
+ ["echo \"uptime\" | sudo su - #{as}", {:shell=>false}]
46
+ end
47
+ end
48
+
49
+ def test_run_without_override
50
+ @ext.run 'uptime'
51
+ assert_equal [%w(uptime) << {}], @ext.invocations[:run].last
52
+ end
53
+
54
+ def test_run_with_override
55
+ @ext.set :override_run_method, :sudo
56
+ @ext.set :override_runnner, :admin
57
+ @ext.run 'uptime'
58
+ assert_equal [%w(uptime)], @ext.invocations[:sudo].last
59
+ end
60
+
61
+ def test_sudo_without_override
62
+ @ext.sudo 'uptime'
63
+ assert_equal [%w(uptime)], @ext.invocations[:sudo].last
64
+ end
65
+
66
+ def test_sudo_with_override
67
+ @ext.set :override_sudo_method, :sudo_as
68
+ @ext.set :override_sudo_runner, :admin
69
+ @ext.sudo 'uptime'
70
+ assert_equal [%w(uptime) << {:as=>:admin}], @ext.invocations[:sudo].last
71
+ @ext.set :override_sudo_method, :sudo_su_to
72
+ @ext.sudo 'uptime'
73
+ assert_equal [["echo \"uptime\" | sudo su - admin", {:shell=>false}]], @ext.invocations[:run].last
74
+ end
75
+
76
+ private
77
+
78
+ def check_run_methods(method,key)
79
+ [:run, :sudo].each do |via|
80
+ @ext.send method, 'uptime'
81
+ assert_equal [%w(uptime) << {:via=>via}], @ext.invocations[key].last
82
+ @ext.set :run_method, :sudo
83
+ end
84
+ [:sudo, :run].each do |via|
85
+ @ext.send method, 'uptime', &block=Proc.new{}
86
+ assert_equal [%w(uptime) << {:via=>via}, block], @ext.invocations[key].last
87
+ @ext.unset :run_method
88
+ end
89
+ @ext.send method, 'uptime', :via=>:sudo
90
+ assert_equal [%w(uptime) << {:via=>:sudo}], @ext.invocations[key].last
91
+ end
92
+
93
+ def check_as_methods(method,key,cmd='uptime',&p)
94
+ p ||= lambda{|c,as| [c, {:as=>as}] }
95
+ [nil, :admin].each do |as|
96
+ @ext.send method,cmd
97
+ assert_equal [p[cmd,as]], @ext.invocations[key].last
98
+ @ext.set :runner, :admin
99
+ end
100
+ @ext.send method, cmd, :as=>:busybody
101
+ assert_equal [p[cmd,:busybody]], @ext.invocations[key].last
102
+ [:admin, nil].each do |as|
103
+ @ext.send method, cmd, &block=Proc.new{}
104
+ assert_equal [p[cmd,as], block], @ext.invocations[key].last
105
+ @ext.unset :runner
106
+ end
107
+ @ext.send method, cmd, :as=>:busybody
108
+ assert_equal [p[cmd,:busybody]], @ext.invocations[key].last
109
+ @ext.send method, :as=>:busybody
110
+ assert_equal [[{:as=>:busybody}]], @ext.invocations[:sudo].last
111
+ end
112
+ end
@@ -2,9 +2,14 @@ require 'stringio'
2
2
  require 'test/unit'
3
3
  require 'rubygems'
4
4
  require 'capistrano/logger'
5
+ require 'capistrano/configuration/variables'
5
6
 
6
7
  class CapistranoMock
7
8
 
9
+ include Capistrano::Configuration::Variables
10
+
11
+ attr_reader :invocations
12
+
8
13
  def logbuf
9
14
  @logbuf ||= StringIO.new
10
15
  end
@@ -17,4 +22,21 @@ class CapistranoMock
17
22
  @logger
18
23
  end
19
24
 
25
+ %w(invoke_command capture stream run).each do |k|
26
+ class_eval %Q{
27
+ def #{k}(*args, &block)
28
+ args = [args]
29
+ args << block if block
30
+ ((@invocations ||= {})[:#{k}] ||= []) << args
31
+ end
32
+ }
33
+ end
34
+
35
+ def sudo(*args, &block)
36
+ return 'sudo' if args.empty?
37
+ args = [args]
38
+ args << block if block
39
+ ((@invocations ||= {})[:sudo] ||= []) << args
40
+ end
41
+
20
42
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 9
9
- version: 0.1.9
8
+ - 10
9
+ version: 0.1.10
10
10
  platform: ruby
11
11
  authors:
12
12
  - Joe Khoobyar
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-15 00:00:00 -04:00
17
+ date: 2010-06-16 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -26,8 +26,8 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
28
  - 2
29
- - 0
30
- version: "2.0"
29
+ - 5
30
+ version: "2.5"
31
31
  type: :runtime
32
32
  version_requirements: *id001
33
33
  - !ruby/object:Gem::Dependency
@@ -75,6 +75,7 @@ files:
75
75
  - lib/capsaicin/sys.rb
76
76
  - lib/capsaicin/ui.rb
77
77
  - test/capsaicin/files/local_test.rb
78
+ - test/capsaicin/invocation_test.rb
78
79
  - test/helper.rb
79
80
  has_rdoc: true
80
81
  homepage: http://github.com/joekhoobyar/capsaicin
@@ -108,4 +109,5 @@ specification_version: 3
108
109
  summary: Joe Khoobyar's spicy capistrano extensions
109
110
  test_files:
110
111
  - test/capsaicin/files/local_test.rb
112
+ - test/capsaicin/invocation_test.rb
111
113
  - test/helper.rb