Skip to content

Commit

Permalink
Use ftype
Browse files Browse the repository at this point in the history
  • Loading branch information
robotdana committed Nov 18, 2023
1 parent 223ec20 commit 9a43543
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 40 deletions.
45 changes: 18 additions & 27 deletions lib/path_list/candidate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ class PathList
# @api private
# The object that gets passed to all {PathList::Matcher} subclasses #match
class Candidate
# :nocov:
if ::RUBY_PLATFORM == 'java' && ::RbConfig::CONFIG['host_os'].match?(/mswin|mingw/)
Autoloader.autoload(self)
include JrubyWindowsFix
end
# :nocov:

attr_reader :full_path

# @param full_path [String] resolved absolute path
Expand All @@ -18,6 +25,7 @@ def initialize(full_path, directory = nil, shebang = nil)

@child_candidates = nil
@children = nil
@ftype = nil
end

# @return [String] full path downcased
Expand Down Expand Up @@ -54,33 +62,16 @@ def children
end
end

# :nocov:
if ::RUBY_PLATFORM == 'java' && ::RbConfig::CONFIG['host_os'].match?(/mswin|mingw/)
# @return [Boolean] whether this path is a directory (false for symlinks to directories)
def directory?
return @directory unless @directory.nil?

@directory = if ::File.symlink?(@full_path)
warn 'Symlink lstat'
warn lstat.inspect
false
else
lstat&.directory? || false
end
end
# :nocov:
else
# @return [Boolean] whether this path is a directory (false for symlinks to directories)
def directory?
return @directory unless @directory.nil?
# @return [Boolean] whether this path is a directory (false for symlinks to directories)
def directory?
return @directory unless @directory.nil?

@directory = lstat&.directory? || false
end
@directory = ftype == 'directory'
end

# @return [Boolean] whether this path exists
def exists?
lstat ? true : false
ftype != 'error'
end

alias_method :original_inspect, :inspect # leftovers:keep
Expand Down Expand Up @@ -112,7 +103,7 @@ def shebang
''
end
rescue ::IOError, ::SystemCallError
@lstat ||= nil
@ftype ||= 'error'
''
ensure
file&.close
Expand All @@ -121,12 +112,12 @@ def shebang

private

def lstat
return @lstat if defined?(@lstat)
def ftype
return @ftype if @ftype

@lstat = ::File.lstat(@full_path)
@ftype = ::File.ftype(@full_path)
rescue ::SystemCallError
@lstat = nil
@ftype = 'error'
end
end
end
32 changes: 32 additions & 0 deletions lib/path_list/candidate/jruby_windows_fix.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# :nocov:
class PathList
class Candidate
# @api private
module JrubyWindowsFix
# @return [Boolean] whether this path is a directory (false for symlinks to directories)
def directory?
return @directory unless @directory.nil?

@directory = if ::File.symlink?(@full_path)
false
else
::File.directory?(@full_path) || false
end
end

# @return [Boolean] whether this path exists
def exists?
return @exists if defined?(@exists)

::File.exist?(@full_path)
end

private

def ftype
raise 'File.ftype follows symlinks in jruby in windows'
end
end
end
end
# :nocov:
23 changes: 10 additions & 13 deletions spec/candidate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,35 +54,35 @@
before { create_file_list 'foo' }

it 'is memoized when true' do
allow(File).to receive(:lstat).and_call_original
allow(File).to receive(:ftype).and_call_original

expect(candidate.exists?).to be true
expect(File).to have_received(:lstat).once
expect(File).to have_received(:ftype).once
expect(candidate.exists?).to be true
expect(File).to have_received(:lstat).once
expect(File).to have_received(:ftype).once
end
end

context 'when the file does not exist' do
let(:full_path) { './foo' }

it 'is memoized when false' do
allow(File).to receive(:lstat).and_call_original
allow(File).to receive(:ftype).and_call_original

expect(candidate.exists?).to be false
expect(File).to have_received(:lstat).with('./foo').once
expect(File).to have_received(:ftype).with('./foo').once
expect(candidate.exists?).to be false
expect(File).to have_received(:lstat).with('./foo').once
expect(File).to have_received(:ftype).with('./foo').once
end

it 'is false when there is an error' do
allow(File).to receive(:lstat).and_call_original
allow(File).to receive(:lstat).with(full_path).and_raise(Errno::EACCES)
allow(File).to receive(:ftype).and_call_original
allow(File).to receive(:ftype).with(full_path).and_raise(Errno::EACCES)

expect(candidate.exists?).to be false
expect(File).to have_received(:lstat).with('./foo').once
expect(File).to have_received(:ftype).with('./foo').once
expect(candidate.exists?).to be false
expect(File).to have_received(:lstat).with('./foo').once
expect(File).to have_received(:ftype).with('./foo').once
end
end
end
Expand Down Expand Up @@ -139,9 +139,6 @@
create_symlink('foo' => 'foo_target')

candidate = described_class.new(File.expand_path('foo'))
expect(File.symlink?('./foo')).to be true
expect(File.stat('./foo')).to have_attributes(directory?: false, symlink?: true)
expect(candidate.send(:lstat)).to have_attributes(directory?: false, symlink?: true)
expect(candidate).not_to be_directory
end
end
Expand Down

0 comments on commit 9a43543

Please sign in to comment.