automateit 0.71104 → 0.71111

Sign up to get free protection for your applications and to get access to all the features.
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