diff --git a/spec/unit/dependency_definition_spec.cr b/spec/unit/dependency_definition_spec.cr index 7e38574e..679c7458 100644 --- a/spec/unit/dependency_definition_spec.cr +++ b/spec/unit/dependency_definition_spec.cr @@ -35,6 +35,11 @@ module Shards # bitbucket urls expect_parses("https://bitbucket.com/foo/bar", "bitbucket", "foo/bar", Any) + # unknown https urls + expect_raises Shards::Error, "Cannot determine resolver for HTTPS URI" do + Shards::DependencyDefinition.parts_from_cli("https://example.com/foo/bar") + end + # Git convenient syntax since resolver matches scheme expect_parses("git://git.example.org/crystal-library.git", "git", "git://git.example.org/crystal-library.git", Any) expect_parses("git@example.org:foo/bar.git", "git", "git@example.org:foo/bar.git", Any) @@ -51,13 +56,19 @@ module Shards expect_parses("..\\relative\\windows", "path", "../relative/windows", Any) {% end %} # Path file schema - expect_parses("file://#{local_relative}", "path", local_relative, Any) + expect_raises Shards::Error, "Invalid file URI" do + Shards::DependencyDefinition.parts_from_cli("file://#{local_relative}") + end + expect_parses("file:#{local_relative}", "path", local_relative, Any) + expect_parses("file:#{local_absolute}", "path", local_absolute, Any) expect_parses("file://#{local_absolute}", "path", local_absolute, Any) # Path resolver syntax expect_parses("path:#{local_absolute}", "path", local_absolute, Any) expect_parses("path:#{local_relative}", "path", local_relative, Any) # Other resolvers short expect_parses("git:git://git.example.org/crystal-library.git", "git", "git://git.example.org/crystal-library.git", Any) + expect_parses("git+https://example.org/foo/bar", "git", "https://example.org/foo/bar", Any) + expect_parses("git:https://example.org/foo/bar", "git", "https://example.org/foo/bar", Any) end end end diff --git a/src/dependency_definition.cr b/src/dependency_definition.cr index 55b20250..bb207045 100644 --- a/src/dependency_definition.cr +++ b/src/dependency_definition.cr @@ -2,7 +2,7 @@ require "./dependency" module Shards class DependencyDefinition - record Parts, resolver_key : String, source : String, requirement : Requirement + record Parts, resolver_key : String, source : String, requirement : Requirement = Any property dependency : Dependency # resolver's key and source are normalized. We preserve the key and source to be used @@ -45,59 +45,51 @@ module Shards # # Split to allow better unit testing. def self.parts_from_cli(value : String) : Parts - resolver_key = nil - source = "" - requirement = Any - - if value.starts_with?("file://") - resolver_key = "path" - source = value[7..-1] # drop "file://" - end - - # relative paths - path = Path[value].to_posix.to_s - if path.starts_with?("./") || path.starts_with?("../") - resolver_key = "path" - source = path - end - uri = URI.parse(value) - if uri.scheme != "file" && uri.host && - (resolver_key = GitResolver::KNOWN_PROVIDERS[uri.host]?) - source = uri.path[1..-1].rchop(".git") # drop first "/"" - end - - if value.starts_with?("git://") - resolver_key = "git" - source = value - end - - if value.starts_with?("git@") - resolver_key = "git" - source = value - end - - unless resolver_key - Resolver.resolver_keys.each do |key| - key_schema = "#{key}:" - if value.starts_with?(key_schema) - resolver_key = key - source = value.sub(key_schema, "") - - # narrow down requirement - if source.includes?("@") - source, version = source.split("@") - requirement = VersionReq.new("~> #{version}") - end - break + case scheme = uri.scheme + when Nil + case value + when .starts_with?("./"), .starts_with?("../") + Parts.new("path", Path[value].to_posix.to_s) + when .starts_with?("git@") + Parts.new("git", value) + else + raise Shards::Error.new("Invalid dependency format: #{value}") + end + when "file" + raise Shards::Error.new("Invalid file URI: #{uri}") if !uri.host.in?(nil, "", "localhost") || uri.port || uri.user + Parts.new("path", uri.path) + when "https" + if resolver_key = GitResolver::KNOWN_PROVIDERS[uri.host]? + Parts.new(resolver_key, uri.path[1..-1].rchop(".git")) # drop first "/"" + else + raise Shards::Error.new("Cannot determine resolver for HTTPS URI: #{value}") + end + when "git" + if uri.host + Parts.new("git", uri.to_s) + else + Parts.new("git", uri.path) + end + when "git+https" + uri.scheme = "https" + Parts.new("git", uri.to_s) + else + if resolver_class = Resolver::RESOLVER_CLASSES[scheme]? + uri.scheme = nil + source = uri.to_s + # narrow down requirement + requirement = Any + if source.includes?("@") + source, version = source.split("@") + requirement = VersionReq.new("~> #{version}") end + + return Parts.new(scheme, source, requirement) end + raise Shards::Error.new("Invalid dependency format: #{value}") end - - raise Shards::Error.new("Invalid dependency format: #{value}") unless resolver_key - - Parts.new(resolver_key: resolver_key, source: source, requirement: requirement) end end end diff --git a/src/resolvers/resolver.cr b/src/resolvers/resolver.cr index b1069f5c..7e9fd462 100644 --- a/src/resolvers/resolver.cr +++ b/src/resolvers/resolver.cr @@ -100,13 +100,9 @@ module Shards end private record ResolverCacheKey, key : String, name : String, source : String - private RESOLVER_CLASSES = {} of String => Resolver.class + RESOLVER_CLASSES = {} of String => Resolver.class private RESOLVER_CACHE = {} of ResolverCacheKey => Resolver - def self.resolver_keys - RESOLVER_CLASSES.keys - end - def self.register_resolver(key, resolver) RESOLVER_CLASSES[key] = resolver end