Skip to content

Commit 1e95757

Browse files
committed
Add parts_from_cli helper method to parse cli arguments
1 parent e74e050 commit 1e95757

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

spec/unit/dependency_spec.cr

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,49 @@ module Shards
7171
parse_dependency({foo: {git: "", tag: "rc-1.0"}}).to_s.should eq("foo (tag rc-1.0)")
7272
parse_dependency({foo: {git: "", commit: "4478d8afe8c728f44b47d3582a270423cd7fc07d"}}).to_s.should eq("foo (commit 4478d8a)")
7373
end
74+
75+
it ".parts_from_cli" do
76+
# GitHub short syntax
77+
Dependency.parts_from_cli("github:foo/bar").should eq({resolver_key: "github", source: "foo/bar", requirement: Any})
78+
Dependency.parts_from_cli("github:Foo/[email protected]").should eq({resolver_key: "github", source: "Foo/Bar", requirement: VersionReq.new("~> 1.2.3")})
79+
80+
# GitHub urls
81+
Dependency.parts_from_cli("https://github.com/foo/bar").should eq({resolver_key: "github", source: "foo/bar", requirement: Any})
82+
Dependency.parts_from_cli("https://github.com/Foo/Bar/commit/000000").should eq({resolver_key: "github", source: "Foo/Bar", requirement: GitCommitRef.new("000000")})
83+
Dependency.parts_from_cli("https://github.com/Foo/Bar/tree/v1.2.3").should eq({resolver_key: "github", source: "Foo/Bar", requirement: GitTagRef.new("v1.2.3")})
84+
Dependency.parts_from_cli("https://github.com/Foo/Bar/tree/some/branch").should eq({resolver_key: "github", source: "Foo/Bar", requirement: GitBranchRef.new("some/branch")})
85+
86+
# GitLab short syntax
87+
Dependency.parts_from_cli("gitlab:foo/bar").should eq({resolver_key: "gitlab", source: "foo/bar", requirement: Any})
88+
89+
# GitLab urls
90+
Dependency.parts_from_cli("https://gitlab.com/foo/bar").should eq({resolver_key: "gitlab", source: "foo/bar", requirement: Any})
91+
92+
# Bitbucket short syntax
93+
Dependency.parts_from_cli("bitbucket:foo/bar").should eq({resolver_key: "bitbucket", source: "foo/bar", requirement: Any})
94+
95+
# bitbucket urls
96+
Dependency.parts_from_cli("https://bitbucket.com/foo/bar").should eq({resolver_key: "bitbucket", source: "foo/bar", requirement: Any})
97+
98+
# Git convenient syntax since resolver matches scheme
99+
Dependency.parts_from_cli("git://git.example.org/crystal-library.git").should eq({resolver_key: "git", source: "git://git.example.org/crystal-library.git", requirement: Any})
100+
101+
# Local paths
102+
local_absolute = File.join(tmp_path, "local")
103+
local_relative = File.join("spec", ".repositories", "local") # rel_path is relative to integration spec
104+
Dir.mkdir_p(local_absolute)
105+
106+
# Path short syntax
107+
Dependency.parts_from_cli(local_absolute).should eq({resolver_key: "path", source: local_absolute, requirement: Any})
108+
Dependency.parts_from_cli(local_relative).should eq({resolver_key: "path", source: local_relative, requirement: Any})
109+
110+
# Path resolver syntax
111+
Dependency.parts_from_cli("path:#{local_absolute}").should eq({resolver_key: "path", source: local_absolute, requirement: Any})
112+
Dependency.parts_from_cli("path:#{local_relative}").should eq({resolver_key: "path", source: local_relative, requirement: Any})
113+
114+
# Other resolvers short
115+
Dependency.parts_from_cli("git:git://git.example.org/crystal-library.git").should eq({resolver_key: "git", source: "git://git.example.org/crystal-library.git", requirement: Any})
116+
end
74117
end
75118
end
76119

src/dependency.cr

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,82 @@ module Shards
1111
def initialize(@name : String, @resolver : Resolver, @requirement : Requirement = Any)
1212
end
1313

14+
# :nodoc:
15+
#
16+
# Parse the dependency from a CLI argument
17+
# and return the parts needed to create the proper dependency.
18+
#
19+
# Split to allow better unit testing.
20+
def self.parts_from_cli(value : String) : {resolver_key: String, source: String, requirement: Requirement}
21+
resolver_key = nil
22+
source = ""
23+
requirement = Any
24+
25+
if File.directory?(value)
26+
resolver_key = "path"
27+
source = value
28+
end
29+
30+
if value.starts_with?("https://github.com")
31+
resolver_key = "github"
32+
uri = URI.parse(value)
33+
source = uri.path[1..-1] # drop first "/""
34+
35+
components = source.split("/")
36+
case components[2]?
37+
when "commit"
38+
source = "#{components[0]}/#{components[1]}"
39+
requirement = GitCommitRef.new(components[3])
40+
when "tree"
41+
source = "#{components[0]}/#{components[1]}"
42+
requirement = if components[3].starts_with?("v")
43+
GitTagRef.new(components[3])
44+
else
45+
GitBranchRef.new(components[3..-1].join("/"))
46+
end
47+
end
48+
end
49+
50+
if value.starts_with?("https://gitlab.com")
51+
resolver_key = "gitlab"
52+
uri = URI.parse(value)
53+
source = uri.path[1..-1] # drop first "/""
54+
end
55+
56+
if value.starts_with?("https://bitbucket.com")
57+
resolver_key = "bitbucket"
58+
uri = URI.parse(value)
59+
source = uri.path[1..-1] # drop first "/""
60+
end
61+
62+
if value.starts_with?("git://")
63+
resolver_key = "git"
64+
source = value
65+
end
66+
67+
unless resolver_key
68+
Resolver.resolver_keys.each do |key|
69+
key_schema = "#{key}:"
70+
if value.starts_with?(key_schema)
71+
resolver_key = key
72+
source = value.sub(key_schema, "")
73+
74+
# narrow down requirement
75+
if source.includes?("@")
76+
source, version = source.split("@")
77+
requirement = VersionReq.new("~> #{version}")
78+
end
79+
80+
break
81+
end
82+
end
83+
end
84+
85+
raise Shards::Error.new("Invalid dependency format: #{value}") unless resolver_key
86+
87+
{resolver_key: resolver_key, source: source, requirement: requirement}
88+
end
89+
1490
def self.from_yaml(pull : YAML::PullParser)
1591
mapping_start = pull.location
1692
name = pull.read_scalar

src/resolvers/resolver.cr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ module Shards
103103
private RESOLVER_CLASSES = {} of String => Resolver.class
104104
private RESOLVER_CACHE = {} of ResolverCacheKey => Resolver
105105

106+
def self.resolver_keys
107+
RESOLVER_CLASSES.keys
108+
end
109+
106110
def self.register_resolver(key, resolver)
107111
RESOLVER_CLASSES[key] = resolver
108112
end

0 commit comments

Comments
 (0)