automateit 0.71104 → 0.71111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,10 @@
1
+ 0.71111:
2
+ Date: Sun, 11 Nov 2007 06:06:27 -0800
3
+ Desc:
4
+ - (+) Improved AccountManager::Etc detection logic, it now tries to run commands rather than relying on blacklists. This better supports Windows and JRuby.
5
+ - (+) Added ShellManager::WhichWindows, it simulates the #which command on Windows.
6
+ - WARNING: AccountManager::POSIX#add_groups_to_user and add_users_to_group
7
+
1
8
  0.71104:
2
9
  Date: Sun, 04 Nov 2007 21:01:10 -0800
3
10
  Desc:
@@ -62,11 +69,11 @@ Thanks for the report, David Brewer.
62
69
  0.71030:
63
70
  Date: Tue, 30 Oct 2007 01:43:02 -0700
64
71
  Desc:
65
- - (%) Fixed bug in AddressManager#add_user when called with multiple groups. Improved AddressManager spec.
72
+ - (%) Fixed bug in AddressManager#add_user when called with multiple groups. Improved AddressManager spec.
66
73
  - (+) Added documentation to Project explaining how to partition recipes, and run recipes from other recipes.
67
- - (+) Added AddressManager::POSIX which provides support for Linux and SunOS, and eliminated the OS-specific drivers for these.
68
- - Added AddressManager::NSCD by extracting methods from old OS-specific drivers.
69
- - Added AddressManager::PasswdExpect which uses Expect for much more reliable password changes.
74
+ - (+) Added AddressManager::POSIX which provides support for Linux and SunOS, and eliminated the OS-specific drivers for these.
75
+ - Added AddressManager::NSCD by extracting methods from old OS-specific drivers.
76
+ - Added AddressManager::PasswdExpect which uses Expect for much more reliable password changes.
70
77
  - Improved AddressManager::PasswdPty by adding retry capability.
71
78
 
72
79
  0.71021:
data/TODO.txt CHANGED
@@ -3,8 +3,12 @@ KEY: Important? Urgent? Easy? 1=yes, 0=no
3
3
  #===[ App ]=============================================================
4
4
 
5
5
  #---[ Quality issues ]--------------------------------------------------
6
- 111 ServiceManager -- Create new #stop_and_start, and #restart as #tell wrapper
6
+ !!! ServiceManager -- Create new #stop_and_start, and add new #restart as #tell wrapper
7
7
  111 ServiceManager -- Write tests for start_and_enable and such
8
+
9
+ !!! AccountManager -- Solaris fails 5% of the time on the last spec.
10
+ !!! AccountManager -- OpenBSD stalls if it thinks a password's quality sucks.
11
+ !!! AccountManager -- OpenBSD fails "should add groups to a user" and "should add users to group"
8
12
  111 PackageManager -- Improve PEAR spec by having it check files with and without channel URL
9
13
  111 AccountManager::NSCD -- Uses "ps -ef", needs abstraction
10
14
 
@@ -25,7 +29,7 @@ KEY: Important? Urgent? Easy? 1=yes, 0=no
25
29
  000 Shell -- Incorporate which.cmd so #which can work on Windows
26
30
 
27
31
  000 Interpreter#invoke and HelpfulERB -- Extract error context code into class
28
- 000 Interpeter -- Implement #clear, #dirty? #track_changes
32
+ 000 Interpeter -- Implement #clear, #dirty? #track_changes
29
33
  000 DatabaseManager -- Design
30
34
  000 SourceManager -- Design
31
35
  000 ScheduleManager -- Design
@@ -50,6 +50,7 @@ class ::AutomateIt::AccountManager::BaseDriver < ::AutomateIt::Plugin::Driver
50
50
  end
51
51
 
52
52
  block.call(username, opts)
53
+ manager.invalidate(:passwd)
53
54
 
54
55
  passwd_opts = {:quiet => opts[:quiet]}
55
56
  manager.passwd(username, opts[:passwd], passwd_opts) if opts[:passwd]
@@ -5,26 +5,17 @@
5
5
  # modifications, such as +add_user+. Platform-specific drivers inherit from
6
6
  # this class and provide methods that perform modifications.
7
7
  class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDriver
8
- depends_on :callbacks => [lambda{AutomateIt::AccountManager::Etc.has_etc?}]
8
+ depends_on :libraries => %w(etc),
9
+ :callbacks => lambda{
10
+ begin
11
+ ! ::Etc.getpwnam(::Etc.getlogin).nil?
12
+ rescue
13
+ false
14
+ end
15
+ }
9
16
 
10
17
  def suitability(method, *args) # :nodoc:
11
- return 1
12
- end
13
-
14
- # Does this platform provide a way of querying users and groups through
15
- # the 'etc' module?
16
- def self.has_etc?
17
- begin
18
- require 'etc'
19
- return defined?(::Etc)
20
- rescue LoadError
21
- return false
22
- end
23
- end
24
-
25
- # Alias for AccountManager::Etc.has_etc?
26
- def has_etc?
27
- self.class.has_etc?
18
+ return available? ? 1 : 0
28
19
  end
29
20
 
30
21
  #.......................................................................
@@ -35,13 +26,13 @@ class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDrive
35
26
  class UserQuery
36
27
  # See AccountManager#users
37
28
  def [](query)
38
- Etc.endpwent
29
+ ::Etc.endpwent
39
30
  begin
40
31
  case query
41
32
  when String
42
- return Etc.getpwnam(query)
33
+ return ::Etc.getpwnam(query)
43
34
  when Fixnum
44
- return Etc.getpwuid(query)
35
+ return ::Etc.getpwuid(query)
45
36
  else
46
37
  raise TypeError.new("unknonwn type for query: #{query.class}")
47
38
  end
@@ -69,13 +60,13 @@ class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDrive
69
60
  class GroupQuery
70
61
  # See AccountManager#groups
71
62
  def [](query)
72
- Etc.endgrent
63
+ ::Etc.endgrent
73
64
  begin
74
65
  case query
75
66
  when String
76
- return Etc.getgrnam(query)
67
+ return ::Etc.getgrnam(query)
77
68
  when Fixnum
78
- return Etc.getgrgid(query)
69
+ return ::Etc.getgrgid(query)
79
70
  else
80
71
  raise TypeError.new("unknonwn type for query: #{query.class}")
81
72
  end
@@ -102,7 +93,7 @@ class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDrive
102
93
  username = pwent.name
103
94
  result = Set.new
104
95
  result << groups[pwent.gid].name if groups[pwent.gid]
105
- Etc.group do |grent|
96
+ ::Etc.group do |grent|
106
97
  result << grent.name if grent.mem.include?(username)
107
98
  end
108
99
  return result.to_a
@@ -117,13 +108,13 @@ class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDrive
117
108
  # See AccountManager#users_to_groups
118
109
  def users_to_groups
119
110
  result = {}
120
- Etc.group do |grent|
111
+ ::Etc.group do |grent|
121
112
  grent.mem.each do |username|
122
113
  result[username] ||= Set.new
123
114
  result[username] << grent.name
124
115
  end
125
116
  end
126
- Etc.passwd do |pwent|
117
+ ::Etc.passwd do |pwent|
127
118
  grent = groups[pwent.gid]
128
119
  unless grent
129
120
  log.fatal(PNOTE+"WARNING: User's default group doesn't exist: user %s, gid %s" % [pwent.name, pwent.gid])
@@ -11,8 +11,10 @@
11
11
  # changed using the AccountManager::PasswdExpect driver, which works properly.
12
12
  class ::AutomateIt::AccountManager::PasswdPTY < ::AutomateIt::AccountManager::BaseDriver
13
13
  depends_on \
14
- :programs => %w(passwd),
15
- :libraries => %w(open3 expect pty)
14
+ :programs => %w(passwd uname),
15
+ :libraries => %w(open3 expect pty),
16
+ # Something is horribly wrong with Ruby PTY on Sun
17
+ :callbacks => lambda { `uname -s`.strip !~ /sunos|solaris|openbsd|freebsd/i }
16
18
 
17
19
  def suitability(method, *args) # :nodoc:
18
20
  # Level must be higher than Linux
@@ -1,7 +1,7 @@
1
1
  # == AccountManager::POSIX
2
2
  #
3
3
  # A POSIX driver for the AccountManager.
4
- class ::AutomateIt::AccountManager::POSIX < ::AutomateIt::AccountManager::Etc
4
+ class ::AutomateIt::AccountManager::POSIX < ::AutomateIt::AccountManager::BaseDriver
5
5
  depends_on :programs => %w(useradd usermod userdel groupadd groupmod groupdel)
6
6
 
7
7
  def suitability(method, *args) # :nodoc:
@@ -123,4 +123,16 @@ class ::AutomateIt::AccountManager::POSIX < ::AutomateIt::AccountManager::Etc
123
123
  end
124
124
  end
125
125
  end
126
+
127
+ # Dispatch common names to Etc, but don't define these methods here because
128
+ # that would make available? and suitability think these exist, when in fact,
129
+ # they're just wrappers.
130
+ def method_missing(symbol, *args, &block)
131
+ case symbol
132
+ when :users, :has_user?, :groups, :has_group?, :groups_for_user, :users_for_group, :users_to_groups
133
+ manager.send(symbol, *args, &block)
134
+ else
135
+ super(symbol, *args, &block)
136
+ end
137
+ end
126
138
  end
@@ -3,6 +3,10 @@ module AutomateIt # :nodoc:
3
3
  #
4
4
  # Various constants.
5
5
  module AutomateIt::Constants
6
+ INSTALL_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
7
+
8
+ HELPERS_DIR = File.join(INSTALL_DIR, "helpers")
9
+
6
10
  # Output prefix for command execution, e.g., "** ls -la"
7
11
  PEXEC = "** "
8
12
 
@@ -174,13 +174,21 @@ module AutomateIt
174
174
  when :directories
175
175
  File.directory?(item)
176
176
  when :programs
177
- # XXX Find less awkward way to check if a program exists. Can't use +shell_manager.which+ because that will use +dispatch+ and go into an infinite loop checking +available?+. The +which+ command isn't available on all platforms, so that failure must be handled as well.
178
- begin
179
- interpreter.shell_manager[:which].which!(item)
180
- true
181
- rescue ArgumentError, NotImplementedError, NoMethodError
182
- false
177
+ # TODO Driver#available? - Find better way to locate the platform's #which driver and use it to check if a program exists. This is tricky because this #available? method is the one that handles detection, yet we have to bypass it.
178
+ result = nil
179
+ for variant in %w(unix windows)
180
+ variant_token = "which_#{variant}".to_sym
181
+ begin
182
+ driver = interpreter.shell_manager[variant_token]
183
+ result = driver.which!(item)
184
+ ### puts "%s : %s for %s" % [variant, result, item]
185
+ break
186
+ rescue ArgumentError, NotImplementedError, NoMethodError => e
187
+ # Exceptions are expected, only print for debugging
188
+ ### puts e.inspect
189
+ end
183
190
  end
191
+ result
184
192
  when :requires, :libraries
185
193
  begin
186
194
  require item
@@ -1,7 +1,7 @@
1
1
  # See AutomateIt::Interpreter for usage information.
2
2
  module AutomateIt # :nodoc:
3
3
  # AutomateIt version
4
- VERSION=Gem::Version.new("0.71104")
4
+ VERSION=Gem::Version.new("0.71111")
5
5
 
6
6
  # Instantiates a new Interpreter. See documentation for
7
7
  # Interpreter#setup.
@@ -267,12 +267,26 @@ end
267
267
  #
268
268
  # Base class for all ShellManager drivers.
269
269
  class AutomateIt::ShellManager::BaseDriver < AutomateIt::Plugin::Driver
270
+ # Returns derived filename to use as a peer given the +source+ and +target+.
271
+ # This is necessary for differentiating between directory and file targets.
272
+ #
273
+ # For example:
274
+ #
275
+ # # Get the peer for an extant target directory:
276
+ # peer_for("foo", "/tmp") # => "/tmp/foo"
277
+ #
278
+ # # Get the peer for anything else:
279
+ # peer_for("foo", "/bar") # => "/bar"
280
+ def peer_for(source, target)
281
+ return FileUtils.send(:fu_each_src_dest0, source, target){|a, b| b}
282
+ end
283
+
284
+ protected
270
285
  def _replace_owner_with_user(opts)
271
286
  value = opts.delete(:owner)
272
287
  opts[:user] = value if value and not opts[:user]
273
288
  return opts
274
289
  end
275
- protected :_replace_owner_with_user
276
290
 
277
291
  # Returns hash of verbosity and preview settings for FileUtils commands.
278
292
  def _fileutils_opts
@@ -281,7 +295,6 @@ class AutomateIt::ShellManager::BaseDriver < AutomateIt::Plugin::Driver
281
295
  opts[:noop] = true if preview?
282
296
  return opts
283
297
  end
284
- protected :_fileutils_opts
285
298
 
286
299
  # Return array of all the directory's top-level contents, including hidden
287
300
  # files with "." prefix on UNIX. Directories are returned just as a name,
@@ -289,26 +302,15 @@ class AutomateIt::ShellManager::BaseDriver < AutomateIt::Plugin::Driver
289
302
  def _directory_contents(directory)
290
303
  return Dir[directory+"/{,.}*"].reject{|t| t =~ /(^|#{File::SEPARATOR})\.{1,2}$/}
291
304
  end
292
- protected :_directory_contents
293
-
294
- # Returns derived filename to use as a peer given the +source+ and +target+.
295
- # This is necessary for differentiating between directory and file targets.
296
- #
297
- # For example:
298
- #
299
- # # Get the peer for an extant target directory:
300
- # peer_for("foo", "/tmp") # => "/tmp/foo"
301
- #
302
- # # Get the peer for anything else:
303
- # peer_for("foo", "/bar") # => "/bar"
304
- def peer_for(source, target)
305
- return FileUtils.send(:fu_each_src_dest0, source, target){|a, b| b}
306
- end
307
305
  end
308
306
 
309
307
  # Drivers
310
308
  require 'automateit/shell_manager/portable'
311
- require 'automateit/shell_manager/which'
309
+
310
+ require 'automateit/shell_manager/which_base'
311
+ require 'automateit/shell_manager/which_unix'
312
+ require 'automateit/shell_manager/which_windows'
313
+
312
314
  require 'automateit/shell_manager/base_link'
313
315
  require 'automateit/shell_manager/symlink'
314
316
  require 'automateit/shell_manager/link'
@@ -0,0 +1,30 @@
1
+ # == ShellManager::WhichBase
2
+ #
3
+ # Provides abstract helper methods for other drivers implementing the +which+.
4
+ class AutomateIt::ShellManager::WhichBase < AutomateIt::ShellManager::BaseDriver
5
+ abstract_driver
6
+
7
+ def suitability(method, *args) # :nodoc:
8
+ # Level must be higher than Portable
9
+ return available? ? 2 : 0
10
+ end
11
+
12
+ # See ShellManager#which!
13
+ def which!(command)
14
+ result = which(command)
15
+ if result.nil?
16
+ raise ArgumentError.new("command not found: #{command}")
17
+ else
18
+ true
19
+ end
20
+ end
21
+
22
+ protected
23
+
24
+ def _which_helper(&block)
25
+ data = block.call
26
+ data.strip! if data
27
+ return (! data.blank? && File.exists?(data)) ? data : nil
28
+ end
29
+
30
+ end
@@ -0,0 +1,16 @@
1
+ # == ShellManager::WhichUnix
2
+ #
3
+ # A ShellManager driver providing access to the +which+ command found on
4
+ # Unix-like systems.
5
+ class AutomateIt::ShellManager::WhichUnix < AutomateIt::ShellManager::WhichBase
6
+ depends_on :programs => %w(which)
7
+
8
+ # Inherits WhichBase#suitability
9
+
10
+ # See ShellManager#which
11
+ def which(command)
12
+ _which_helper do
13
+ `which #{command} 2>&1`
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # == ShellManager::WhichWindows
2
+ #
3
+ # A ShellManager driver providing access to +which+ command by faking it on
4
+ # Windows systems.
5
+ class ::AutomateIt::ShellManager::WhichWindows < ::AutomateIt::ShellManager::WhichBase
6
+ WHICH_HELPER = File.join(::AutomateIt::Constants::HELPERS_DIR, "which.cmd")
7
+
8
+ # FIXME how to detect windows through Java?
9
+ depends_on :callbacks => lambda { RUBY_PLATFORM =~ /mswin/i }
10
+
11
+ # Inherits WhichBase#suitability
12
+
13
+ # See ShellManager#which
14
+ def which(command)
15
+ _which_helper do
16
+ data = `#{WHICH_HELPER} #{command} 2>&1`
17
+ end
18
+ end
19
+ end
20
+
@@ -4,7 +4,7 @@ if not INTERPRETER.euid?
4
4
  puts "NOTE: Can't check 'euid' on this platform, #{__FILE__}"
5
5
  elsif not INTERPRETER.superuser?
6
6
  puts "NOTE: Must be root to check #{__FILE__}"
7
- elsif not INTERPRETER.account_manager.available?(:add_user)
7
+ elsif (INTERPRETER.account_manager.available?(:users) && INTERPRETER.account_manager.available?(:add_user)) != true
8
8
  puts "NOTE: Can't find AccountManager for this platform, #{__FILE__}"
9
9
  else
10
10
  describe AutomateIt::AccountManager do
@@ -20,7 +20,7 @@ else
20
20
  # Some OSes are limited to 8 character names :(
21
21
  @username = "aitestus"
22
22
  @groupname = "aitestgr"
23
- @password = "automateit"
23
+ @password = "WejVotyejik2"
24
24
 
25
25
  begin
26
26
  raise "User named '#{@username}' found. If this isn't a real user, delete it so that the test can contineu. If this is a real user, change the spec to test with a user that shouldn't exist." if @m.users[@username]
@@ -54,7 +54,7 @@ else
54
54
  # work around this by using a directory we know can be used
55
55
  home = INTERPRETER.tagged?(:sunos) ? "/var/tmp/#{@username}" : nil
56
56
 
57
- defaults = { :passwd => "asdf", :shell => "/bin/false", :home => home,
57
+ defaults = { :passwd => "skosk8osWu", :shell => "/bin/false", :home => home,
58
58
  :quiet => @quiet }
59
59
 
60
60
  return @m.add_user(@username, defaults.merge(opts))
@@ -69,12 +69,6 @@ else
69
69
  return @m.add_group(@groupname, :members => @username)
70
70
  end
71
71
 
72
- unless INTERPRETER.tagged?("windows | darwin")
73
- it "should have Etc support on Unix-like platforms" do
74
- @m.driver_for(:users).should have_etc
75
- end
76
- end
77
-
78
72
  it "should find root user" do
79
73
  entry = @m.users["root"]
80
74
  entry.should_not be_nil
@@ -267,12 +261,15 @@ else
267
261
  def change_password_with(object)
268
262
  add_user if @independent
269
263
 
270
- # TODO This isn't portable
271
264
  def extract_pwent(username)
272
- for filename in %w(/etc/shadow /etc/passwd)
265
+ # TODO Not portable.
266
+ for filename in %w(/etc/master.passwd /etc/shadow /etc/passwd)
273
267
  next unless File.exist?(filename)
274
268
  return File.read(filename).split(/\n/).grep(/^#{username}\b/)
275
269
  end
270
+
271
+ # Fails on SunOS which returns "x"
272
+ #::Etc.getpwnam(username).passwd
276
273
  end
277
274
 
278
275
  before = extract_pwent(@username)
@@ -15,12 +15,18 @@ describe AutomateIt::ShellManager, " with sh and which" do
15
15
  it_should_behave_like "AutomateIt::ShellManager"
16
16
 
17
17
  begin
18
- INTERPRETER.which("true")
19
- INTERPRETER.which("false")
18
+ if INTERPRETER.tagged?(:windows)
19
+ it "should run shell commands and detect their exit status (sh)" do
20
+ @m.sh("dir > nul").should be_true
21
+ end
22
+ else
23
+ INTERPRETER.which!("true")
24
+ INTERPRETER.which!("false")
20
25
 
21
- it "should run shell commands and detect their exit status (sh)" do
22
- @m.sh("true").should be_true
23
- @m.sh("false").should be_false
26
+ it "should run shell commands and detect their exit status (sh)" do
27
+ @m.sh("true").should be_true
28
+ @m.sh("false").should be_false
29
+ end
24
30
  end
25
31
  rescue NotImplementedError
26
32
  puts "NOTE: Can't check 'sh' on this platform, #{__FILE__}"
@@ -30,7 +36,8 @@ describe AutomateIt::ShellManager, " with sh and which" do
30
36
  puts "NOTE: Can't use 'which' on this platform in #{__FILE__}"
31
37
  else
32
38
  it "should find which program is in the path (which)" do
33
- @m.which("sh").match(/.\/sh$/).nil?.should be_false
39
+ cmd = "ruby"
40
+ @m.which(cmd).match(/#{cmd}/).nil?.should be_false
34
41
  end
35
42
 
36
43
  it "should not find programs that aren't in the path (which)" do
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: automateit
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.71104"
7
- date: 2007-11-04 00:00:00 -07:00
6
+ version: "0.71111"
7
+ date: 2007-11-12 00:00:00 -08:00
8
8
  summary: AutomateIt is an open source tool for automating the setup and maintenance of servers, applications and their dependencies.
9
9
  require_paths:
10
10
  - lib
@@ -119,12 +119,12 @@ files:
119
119
  - lib/automateit/service_manager/sysv.rb
120
120
  - lib/automateit/service_manager/chkconfig.rb
121
121
  - lib/automateit/service_manager/update_rcd.rb
122
+ - lib/automateit/account_manager/posix.rb
122
123
  - lib/automateit/account_manager/nscd.rb
123
124
  - lib/automateit/account_manager/base.rb
125
+ - lib/automateit/account_manager/etc.rb
124
126
  - lib/automateit/account_manager/passwd_expect.rb
125
- - lib/automateit/account_manager/posix.rb
126
127
  - lib/automateit/account_manager/passwd_pty.rb
127
- - lib/automateit/account_manager/etc.rb
128
128
  - lib/automateit/platform_manager/debian.rb
129
129
  - lib/automateit/platform_manager/struct.rb
130
130
  - lib/automateit/platform_manager/windows.rb
@@ -143,10 +143,12 @@ files:
143
143
  - lib/automateit/address_manager/freebsd.rb
144
144
  - lib/automateit/address_manager/openbsd.rb
145
145
  - lib/automateit/shell_manager/portable.rb
146
- - lib/automateit/shell_manager/which.rb
147
146
  - lib/automateit/shell_manager/symlink.rb
148
147
  - lib/automateit/shell_manager/link.rb
149
148
  - lib/automateit/shell_manager/base_link.rb
149
+ - lib/automateit/shell_manager/which_windows.rb
150
+ - lib/automateit/shell_manager/which_unix.rb
151
+ - lib/automateit/shell_manager/which_base.rb
150
152
  - lib/automateit/tag_manager/struct.rb
151
153
  - lib/automateit/tag_manager/yaml.rb
152
154
  - lib/automateit/tag_manager/tag_parser.rb
@@ -158,7 +160,6 @@ files:
158
160
  - misc/index_gem_repository.rb
159
161
  - misc/setup_rubygems.sh
160
162
  - misc/setup_egg.rb
161
- - misc/which.cmd
162
163
  - misc/setup_gem_dependencies.sh
163
164
  - misc/setup_ruby-dbi.rb
164
165
  - spec/spec_helper.rb
metadata.gz.sig CHANGED
Binary file
@@ -1,25 +0,0 @@
1
- # == ShellManager::Which
2
- #
3
- # A ShellManager driver providing access to the +which+ command found on
4
- # Unix-like systems.
5
- class AutomateIt::ShellManager::Which < AutomateIt::ShellManager::BaseDriver
6
- depends_on :programs => %w(which)
7
-
8
- def suitability(method, *args) # :nodoc:
9
- # Level must be higher than Portable
10
- return available? ? 2 : 0
11
- end
12
-
13
- # See ShellManager#which
14
- def which(command)
15
- data = `which "#{command}" 2>&1`.chomp
16
- return (! data.blank? && File.exists?(data)) ? data : nil
17
- end
18
-
19
- # See ShellManager#which!
20
- def which!(command)
21
- if which(command).nil?
22
- raise ArgumentError.new("command not found: #{command}")
23
- end
24
- end
25
- end
@@ -1,6 +0,0 @@
1
- @ rem "which" workalike for Windows. Searches current directory and PATH for all extensions, stops after first match, and returns meaningful exit value for "system" or "ERRORLEVEL" checks.
2
- @setlocal
3
- @set P2=.;%PATH%
4
- @for %%e in (%PATHEXT%) do @for %%i in (%1%%e) do @if NOT "%%~$P2:i"=="" echo %%~$P2:i && goto end
5
- @exit 1
6
- :end