Skip to content

Commit

Permalink
Merge pull request #7758 from asterite/bug/crystal-path-relative
Browse files Browse the repository at this point in the history
Compiler: fix require relative path resolution
  • Loading branch information
asterite authored May 10, 2019
2 parents 85ad608 + 2f53e5b commit bbffbe0
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 54 deletions.
3 changes: 3 additions & 0 deletions spec/compiler/crystal_path/crystal_path_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ describe Crystal::CrystalPath do
assert_doesnt_find "./crystal_path_spec.cr", relative_to: "test_files/file_one.cr"
assert_doesnt_find "../crystal_path/test_files/file_one"

# Don't find relative filenames in src or shards
assert_doesnt_find "../../src/file_three", relative_to: "test_files/test_folder/test_folder.cr"

it "prints an explanatory message for non-relative requires" do
crystal_path = Crystal::CrystalPath.new(__DIR__)
ex = expect_raises Exception, /If you're trying to require a shard/ do
Expand Down
2 changes: 1 addition & 1 deletion spec/std/http/web_socket_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ require "./spec_helper"
require "../spec_helper"
require "http/web_socket"
require "random/secure"
require "../../../support/ssl"
require "../../support/ssl"

private def assert_text_packet(packet, size, final = false)
assert_packet packet, HTTP::WebSocket::Protocol::Opcode::TEXT, size, final: final
Expand Down
2 changes: 1 addition & 1 deletion spec/std/kernel_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "spec"
require "../../spec_helper"
require "../spec_helper"

describe "exit" do
it "exits normally with status 0" do
Expand Down
113 changes: 61 additions & 52 deletions src/compiler/crystal/crystal_path.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,60 +45,69 @@ module Crystal
end

private def find_in_path_relative_to_dir(filename, relative_to)
if relative_to.is_a?(String)
# Check if it's a wildcard.
if filename.ends_with?("/*") || (recursive = filename.ends_with?("/**"))
filename_dir_index = filename.rindex('/').not_nil!
filename_dir = filename[0..filename_dir_index]
relative_dir = "#{relative_to}/#{filename_dir}"
if File.exists?(relative_dir)
files = [] of String
gather_dir_files(relative_dir, files, recursive)
return files
end
else
relative_filename = "#{relative_to}/#{filename}"
return unless relative_to.is_a?(String)

# Check if it's a wildcard.
if filename.ends_with?("/*") || (recursive = filename.ends_with?("/**"))
filename_dir_index = filename.rindex('/').not_nil!
filename_dir = filename[0..filename_dir_index]
relative_dir = "#{relative_to}/#{filename_dir}"
if File.exists?(relative_dir)
files = [] of String
gather_dir_files(relative_dir, files, recursive)
return files
end

# Check if .cr file exists.
relative_filename_cr = relative_filename.ends_with?(".cr") ? relative_filename : "#{relative_filename}.cr"
if File.exists?(relative_filename_cr)
return make_relative_unless_absolute relative_filename_cr
end
return nil
end

if slash_index = filename.index('/')
# If it's "foo/bar/baz", check if "foo/src/bar/baz.cr" exists (for a shard, non-namespaced structure)
before_slash, after_slash = filename.split('/', 2)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

# Then check if "foo/src/foo/bar/baz.cr" exists (for a shard, namespaced structure)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{before_slash}/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo/bar/baz", check if "foo/bar/baz/baz.cr" exists (std, nested)
basename = File.basename(relative_filename)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{filename}/#{basename}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo/bar/baz", check if "foo/src/foo/bar/baz/baz.cr" exists (shard, non-namespaced, nested)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{after_slash}/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo/bar/baz", check if "foo/src/foo/bar/baz/baz.cr" exists (shard, namespaced, nested)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{before_slash}/#{after_slash}/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)
else
basename = File.basename(relative_filename)

# If it's "foo", check if "foo/foo.cr" exists (for the std, nested)
absolute_filename = make_relative_unless_absolute("#{relative_filename}/#{basename}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo", check if "foo/src/foo.cr" exists (for a shard)
absolute_filename = make_relative_unless_absolute("#{relative_filename}/src/#{basename}.cr")
return absolute_filename if File.exists?(absolute_filename)
end
end
relative_filename = "#{relative_to}/#{filename}"

# Check if .cr file exists.
relative_filename_cr = relative_filename.ends_with?(".cr") ? relative_filename : "#{relative_filename}.cr"
if File.exists?(relative_filename_cr)
return make_relative_unless_absolute relative_filename_cr
end

filename_is_relative = filename.starts_with?('.')

if !filename_is_relative && (slash_index = filename.index('/'))
# If it's "foo/bar/baz", check if "foo/src/bar/baz.cr" exists (for a shard, non-namespaced structure)
before_slash, after_slash = filename.split('/', 2)

absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

# Then check if "foo/src/foo/bar/baz.cr" exists (for a shard, namespaced structure)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{before_slash}/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo/bar/baz", check if "foo/bar/baz/baz.cr" exists (std, nested)
basename = File.basename(relative_filename)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{filename}/#{basename}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo/bar/baz", check if "foo/src/foo/bar/baz/baz.cr" exists (shard, non-namespaced, nested)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{after_slash}/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

# If it's "foo/bar/baz", check if "foo/src/foo/bar/baz/baz.cr" exists (shard, namespaced, nested)
absolute_filename = make_relative_unless_absolute("#{relative_to}/#{before_slash}/src/#{before_slash}/#{after_slash}/#{after_slash}.cr")
return absolute_filename if File.exists?(absolute_filename)

return nil
end

basename = File.basename(relative_filename)

# If it's "foo", check if "foo/foo.cr" exists (for the std, nested)
absolute_filename = make_relative_unless_absolute("#{relative_filename}/#{basename}.cr")
return absolute_filename if File.exists?(absolute_filename)

unless filename_is_relative
# If it's "foo", check if "foo/src/foo.cr" exists (for a shard)
absolute_filename = make_relative_unless_absolute("#{relative_filename}/src/#{basename}.cr")
return absolute_filename if File.exists?(absolute_filename)
end

nil
Expand Down

0 comments on commit bbffbe0

Please sign in to comment.