Skip to content

Commit

Permalink
Implement the new path search algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Oct 6, 2016
1 parent 3525bcd commit fece2f7
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 109 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ADD . /opt/crystal-head

WORKDIR /opt/crystal-head
ENV CRYSTAL_CONFIG_VERSION HEAD
ENV CRYSTAL_CONFIG_PATH libs:/opt/crystal-head/src:/opt/crystal-head/libs
ENV CRYSTAL_CONFIG_PATH libs:lib:/opt/crystal-head/src:/opt/crystal-head/libs
ENV LIBRARY_PATH /opt/crystal/embedded/lib
ENV PATH /opt/crystal-head/bin:/opt/llvm-3.5.0-1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Expand Down
2 changes: 1 addition & 1 deletion bin/crystal
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ SCRIPT_ROOT="$(dirname "$SCRIPT_PATH")"
CRYSTAL_ROOT="$(dirname "$SCRIPT_ROOT")"
CRYSTAL_DIR="$CRYSTAL_ROOT/.build"

export CRYSTAL_PATH=$CRYSTAL_ROOT/src:libs
export CRYSTAL_PATH=$CRYSTAL_ROOT/src:libs:lib

if [ -x "$CRYSTAL_DIR/crystal" ]
then
Expand Down
181 changes: 80 additions & 101 deletions spec/compiler/crystal_path/crystal_path_spec.cr
Original file line number Diff line number Diff line change
@@ -1,114 +1,93 @@
require "../../spec_helper"

describe Crystal::CrystalPath do
it "finds file with .cr extension" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "test_files/file_one.cr"
matches.should eq(["#{__DIR__}/test_files/file_one.cr"])
end

it "finds file without .cr extension" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "test_files/file_one"
matches.should eq(["#{__DIR__}/test_files/file_one.cr"])
end

it "finds all files with *" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "test_files/*"
matches.should eq([
"#{__DIR__}/test_files/file_one.cr",
"#{__DIR__}/test_files/file_two.cr",
])
end

it "finds all files with **" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "test_files/**"
matches.should eq([
"#{__DIR__}/test_files/file_one.cr",
"#{__DIR__}/test_files/file_two.cr",
"#{__DIR__}/test_files/test_folder/file_three.cr",
"#{__DIR__}/test_files/test_folder/test_folder.cr",
])
end

it "finds file in directory with its basename" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "test_files/test_folder"
matches.should eq([
"#{__DIR__}/test_files/test_folder/test_folder.cr",
])
end

it "doesn't find file relative to another one if not using ./" do
path = Crystal::CrystalPath.new(__DIR__)
expect_raises Exception, /can't find file/ do
path.find "file_two.cr", relative_to: "#{__DIR__}/test_files/file_one.cr"
end
end

it "finds file relative to another one if using ./" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "./file_two.cr", relative_to: "#{__DIR__}/test_files/file_one.cr"
matches.should eq([
"#{__DIR__}/test_files/file_two.cr",
])
private def assert_finds(search, results, relative_to = nil, path = __DIR__, file = __FILE__, line = __LINE__)
it "finds #{search.inspect}", file, line do
crystal_path = Crystal::CrystalPath.new(path)
relative_to = "#{__DIR__}/#{relative_to}" if relative_to
results = results.map { |result| "#{__DIR__}/#{result}" }
matches = crystal_path.find search, relative_to: relative_to
matches.should eq(results)
end
end

it "doesn't find file relative to another one with directory if not using ./" do
path = Crystal::CrystalPath.new(__DIR__)
private def assert_doesnt_find(search, relative_to = nil, path = __DIR__, file = __FILE__, line = __LINE__)
it "doesn't finds #{search.inspect}", file, line do
crystal_path = Crystal::CrystalPath.new(path)
relative_to = "#{__DIR__}/#{relative_to}" if relative_to
expect_raises Exception, /can't find file/ do
path.find "test_folder/file_three.cr", relative_to: "#{__DIR__}/test_files/file_one.cr"
crystal_path.find search, relative_to: relative_to
end
end
end

it "finds file relative to another one with directory if using ./" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "./test_folder/file_three.cr", relative_to: "#{__DIR__}/test_files/file_one.cr"
matches.should eq([
"#{__DIR__}/test_files/test_folder/file_three.cr",
])
end
describe Crystal::CrystalPath do
assert_finds "test_files/file_one.cr", ["test_files/file_one.cr"]
assert_finds "test_files/file_one", ["test_files/file_one.cr"]
assert_finds "test_files/*", [
"test_files/file_one.cr",
"test_files/file_two.cr",
]
assert_finds "test_files/**", [
"test_files/file_one.cr",
"test_files/file_two.cr",
"test_files/src/file_three.cr",
"test_files/src/test_files.cr",
"test_files/src/test_files/file_four.cr",
"test_files/src/test_files/another/another.cr",
"test_files/src/yet_another/yet_another.cr",
"test_files/test_folder/file_three.cr",
"test_files/test_folder/test_folder.cr",
]
assert_finds "./file_two.cr", relative_to: "test_files/file_one.cr", results: [
"test_files/file_two.cr",
]
assert_finds "./test_folder/file_three.cr", relative_to: "test_files/file_one.cr", results: [
"test_files/test_folder/file_three.cr",
]
assert_finds "./test_folder/*", relative_to: "test_files/file_one.cr", results: [
"test_files/test_folder/file_three.cr",
"test_files/test_folder/test_folder.cr",
]
assert_finds "../**", relative_to: "test_files/test_folder/file_three.cr", results: [
"test_files/file_one.cr",
"test_files/file_two.cr",
"test_files/src/file_three.cr",
"test_files/src/test_files.cr",
"test_files/src/test_files/file_four.cr",
"test_files/src/test_files/another/another.cr",
"test_files/src/yet_another/yet_another.cr",
"test_files/test_folder/file_three.cr",
"test_files/test_folder/test_folder.cr",
]
assert_finds "../test_folder", relative_to: "test_files/test_folder/file_three.cr", results: [
"test_files/test_folder/test_folder.cr",
]

it "doesn't inds files with * relative to another one if not using ./" do
path = Crystal::CrystalPath.new(__DIR__)
expect_raises Exception, /can't find file/ do
path.find "test_folder/*", relative_to: "#{__DIR__}/test_files/file_one.cr"
end
end
# For `require "foo"`:
# 1. foo.cr (to find something in the standard library)
assert_finds "crystal_path_spec", ["crystal_path_spec.cr"]
# 2. foo/src/foo.cr (to find something in a shard)
assert_finds "test_files", ["test_files/src/test_files.cr"]

it "finds files with * relative to another one if using ./" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "./test_folder/*", relative_to: "#{__DIR__}/test_files/file_one.cr"
matches.should eq([
"#{__DIR__}/test_files/test_folder/file_three.cr",
"#{__DIR__}/test_files/test_folder/test_folder.cr",
])
end
# For `require "foo/bar"`:
# 1. foo/bar.cr (to find something in the standard library)
assert_finds "test_files/file_one", ["test_files/file_one.cr"]
# 2. foo/src/bar.cr (to find something in a shard, non-namespaced structure)
assert_finds "test_files/file_three", ["test_files/src/file_three.cr"]
# 3. foo/src/foo/bar.cr (to find something in a shard, namespaced structure)
assert_finds "test_files/file_four", ["test_files/src/test_files/file_four.cr"]

it "finds files with ** relative to another one" do
path = Crystal::CrystalPath.new(__DIR__)
matches = path.find "../**", relative_to: "#{__DIR__}/test_files/test_folder/file_three.cr"
matches.should eq([
"#{__DIR__}/test_files/file_one.cr",
"#{__DIR__}/test_files/file_two.cr",
"#{__DIR__}/test_files/test_folder/file_three.cr",
"#{__DIR__}/test_files/test_folder/test_folder.cr",
])
end
# Nested searches
# a/1. foo.cr (to find something in the standard library (nested))
assert_finds "other_test_files", ["other_test_files/other_test_files.cr"]
# b/2. foo/src/bar/bar.cr (to find something in a shard, non-namespaced structure, nested)
assert_finds "test_files/yet_another", ["test_files/src/yet_another/yet_another.cr"]
# b/3. foo/src/foo/bar/bar.cr (to find something in a shard, namespaced structure, nested)
assert_finds "test_files/another", ["test_files/src/test_files/another/another.cr"]

it "doesn't find file with .cr extension" do
path = Crystal::CrystalPath.new(__DIR__)
expect_raises Exception, /can't find file/ do
path.find "test_files/missing_file.cr"
end
end

it "ignore an empty directory path" do
path = Crystal::CrystalPath.new(":")
expect_raises Exception, /can't find file/ do
path.find __FILE__[1..-1]
end
end
assert_doesnt_find "file_two.cr"
assert_doesnt_find "test_folder/file_three.cr"
assert_doesnt_find "test_folder/*", relative_to: "#{__DIR__}/test_files/file_one.cr"
assert_doesnt_find "test_files/missing_file.cr"
assert_doesnt_find __FILE__[1..-1], path: ":"
end
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
36 changes: 30 additions & 6 deletions src/compiler/crystal/crystal_path.cr
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,38 @@ module Crystal
return make_relative_unless_absolute relative_filename_cr
end

# If it's a directory, we check if a .cr file with a name the same as the
# directory basename exists, and we require that one.
if Dir.exists?(relative_filename)
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")
if File.exists?(absolute_filename)
return absolute_filename
end
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
end
Expand Down
1 change: 1 addition & 0 deletions src/compiler/crystal/tools/init/template/gitignore.ecr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/doc/
/libs/
/lib/
/.crystal/
/.shards/

Expand Down

0 comments on commit fece2f7

Please sign in to comment.