-
Notifications
You must be signed in to change notification settings - Fork 0
/
ref.cr
191 lines (162 loc) · 4.52 KB
/
ref.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
class Repo
struct Ref
include JSON::Serializable
include Comparable(self)
PROVIDER_RESOLVERS = {"github", "gitlab", "bitbucket"}
getter resolver : String
getter url : String
def initialize(@resolver : String, @url : String)
raise "Unknown resolver #{@resolver}" unless RESOLVERS.includes?(@resolver)
if provider_resolver?
raise "Invalid url for resolver #{@resolver}: #{@url.inspect}" unless @url =~ /^[A-Za-z0-9_\-.]{1,100}\/[A-Za-z0-9_\-.]{1,100}$/
end
end
def self.new(url : String) : self
new URI.parse(url)
end
def self.new(uri : URI) : self
case uri.host
when "github.com", "www.github.com"
if path = extract_org_repo_url(uri)
return new("github", path)
end
when "gitlab.com", "www.gitlab.com"
if path = extract_org_repo_url(uri)
return new("gitlab", path)
end
when "bitbucket.com", "www.bitbucket.com"
if path = extract_org_repo_url(uri)
return new("bitbucket", path)
end
else
# fall through
end
path = uri.path
if path.nil? || path.empty? || path == "/"
raise "Invalid url for resolver git: #{uri.to_s.inspect}"
end
new("git", uri.to_s)
end
def self.parse(string : String)
PROVIDER_RESOLVERS.each do |resolver|
if string.starts_with?(resolver)
size = resolver.bytesize
if string.byte_at(size) == ':'.ord
size += 1
return new(resolver, string.byte_slice(size, string.bytesize - size))
end
end
end
new(string)
end
# Returns `true` if `resolver` is any of `PROVIDER_RESOLVER`.
def provider_resolver? : Bool
PROVIDER_RESOLVERS.includes?(@resolver)
end
def to_uri : URI
if provider_resolver?
# FIXME: Leading slash should not be needed
URI.new("https", "#{resolver}.com", path: "/#{url}")
else
URI.parse(url)
end
end
private def self.extract_org_repo_url(uri)
path = uri.path.not_nil!.strip('/').rchop(".git")
if path.count('/') == 1
path
end
end
def_equals_and_hash resolver, url
def name
uri = URI.parse(url)
File.basename(uri.path).rchop('/').rchop(".git")
end
def owner
if provider_resolver?
Path.posix(url).dirname
end
end
def nice_url
return url if provider_resolver? || !resolvable?
url.lstrip("https://").lstrip("http://").rstrip("/").rstrip(".git")
end
def slug
if provider_resolver?
"#{resolver}.com/#{url}"
else
nice_url
end
end
def base_url_source(refname = nil)
refname = normalize_refname(refname)
case resolver
when "bitbucket"
url = to_uri
url.path += "/src/#{refname}/"
url
when "github"
url = to_uri
url.path += "/tree/#{refname}/"
url
when "gitlab"
# gitlab doesn't necessarily need the `-` component but they use it by default
# and it seems reasonable to be safe of any ambiguities
url = to_uri
url.path += "/-/tree/#{refname}/"
url
else
nil
end
end
def base_url_raw(refname = nil)
refname = normalize_refname(refname)
case resolver
when "github", "bitbucket"
url = to_uri
url.path += "/raw/#{refname}/"
url
when "gitlab"
# gitlab doesn't necessarily need the `-` component but they use it by default
# and it seems reasonable to be safe of any ambiguities
url = to_uri
url.path += "/-/raw/#{refname}/"
url
else
nil
end
end
private def normalize_refname(refname)
case refname
when Nil, "HEAD"
"master"
else
refname
end
end
def resolvable?
provider_resolver? || url.starts_with?("http://") || url.starts_with?("https://")
end
def <=>(other : self)
result = name.compare(other.name, case_insensitive: true)
return result unless result == 0
if provider_resolver? && other.provider_resolver?
result = url.compare(other.url, case_insensitive: true)
return result unless result == 0
resolver <=> other.resolver
else
slug <=> other.slug
end
end
def to_s(io : IO)
io << resolver
io << ":"
@url.dump_unquoted(io)
end
def inspect(io : IO)
io << "#<Repo::Ref "
to_s(io)
io << ">"
end
end
end