Skip to content

Commit 7921d2b

Browse files
KristofferCKristofferC
authored andcommitted
fix another URL scheme parsing in the repl mode (#4450)
(cherry picked from commit 946b4e1)
1 parent 2dcc3e5 commit 7921d2b

File tree

3 files changed

+63
-12
lines changed

3 files changed

+63
-12
lines changed

src/REPLMode/argument_parsers.jl

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,46 @@ end
3434

3535
# Simple URL detection
3636
function looks_like_url(str::String)
37-
return startswith(str, "http://") || startswith(str, "https://") ||
38-
startswith(str, "git@") || startswith(str, "ssh://") ||
39-
contains(str, ".git")
37+
if startswith(str, "http://") || startswith(str, "https://") ||
38+
startswith(str, "git@") || startswith(str, "ssh://") ||
39+
contains(str, ".git")
40+
return true
41+
end
42+
43+
# Check for user@host:path pattern (SSH URL with user)
44+
# This handles cases like: [email protected]:PackageName.jl
45+
# The host part should not contain / or @ characters, and should come before the :
46+
at_pos = findfirst('@', str)
47+
if at_pos !== nothing
48+
colon_pos = findnext(':', str, nextind(str, at_pos))
49+
if colon_pos !== nothing
50+
host_part = str[nextind(str, at_pos):(prevind(str, colon_pos))]
51+
# Host should not contain / (which would suggest this is package@version:subdir syntax)
52+
# and should look like a hostname or IP address (no spaces, etc.)
53+
# Additionally, exclude things that look like version numbers (e.g., "1.0", "1.0.0")
54+
# by checking if the host contains only digits and dots (which would be a version or IP)
55+
# If it's all digits and dots, it must have at least 3 dots to be an IP (X.X.X.X)
56+
if !contains(host_part, '/') && !contains(host_part, ' ') && !isempty(host_part)
57+
# Check if this looks like a version number (e.g., "1.0", "1.0.0")
58+
# vs an IP address (e.g., "10.20.30.40") or hostname (e.g., "server.com")
59+
if all(c -> isdigit(c) || c == '.', host_part)
60+
# All digits and dots - could be version or IP
61+
# Count dots: version has 1-2 dots, IP has 3 dots
62+
dot_count = count(==('.'), host_part)
63+
if dot_count >= 3
64+
# Likely an IP address (X.X.X.X)
65+
return true
66+
end
67+
# else: likely a version number, not a URL
68+
else
69+
# Contains letters or other chars - likely a hostname
70+
return true
71+
end
72+
end
73+
end
74+
end
75+
76+
return false
4077
end
4178

4279
# Simple path detection
@@ -119,14 +156,13 @@ end
119156
function is_url_structure_colon(input::String, colon_pos::Int)
120157
after_colon = input[nextind(input, colon_pos):end]
121158

122-
# Check for git@host:path syntax
123-
if startswith(input, "git@")
124-
at_pos = findfirst('@', input)
125-
if at_pos !== nothing
126-
between_at_colon = input[nextind(input, at_pos):prevind(input, colon_pos)]
127-
if !contains(between_at_colon, '/')
128-
return true
129-
end
159+
# Check for user@host:path syntax (including git@host:path)
160+
at_pos = findfirst('@', input)
161+
if at_pos !== nothing && at_pos < colon_pos
162+
between_at_colon = input[nextind(input, at_pos):prevind(input, colon_pos)]
163+
# If there's no '/' between @ and :, this colon is part of the SSH URL structure
164+
if !contains(between_at_colon, '/')
165+
return true
130166
end
131167
end
132168

src/utils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function linewrap(str::String; io = stdout_f(), padding = 0, width = Base.displa
2424
return lines
2525
end
2626

27-
const URL_regex = r"((file|git|ssh|http(s)?)|(git@[\w\-\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)?(/)?"x
27+
const URL_regex = r"((file|git|ssh|http(s)?)|([\w\-\.]+@[\w\-\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)?(/)?"x
2828
isurl(r::String) = occursin(URL_regex, r)
2929

3030
stdlib_dir() = normpath(joinpath(Sys.BINDIR::String, "..", "share", "julia", "stdlib", "v$(VERSION.major).$(VERSION.minor)"))

test/new.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,21 @@ end
11171117
@test args[1].rev == "branch-name"
11181118
end
11191119

1120+
# Test SSH URLs with IP addresses (issue #1822)
1121+
@testset "SSH URLs with IP addresses" begin
1122+
# Test that user@host:path URLs with IP addresses are parsed correctly as complete URLs
1123+
api, args, opts = first(Pkg.pkg"add [email protected]:PackageName.jl")
1124+
@test api == Pkg.add
1125+
@test length(args) == 1
1126+
@test args[1].url == "[email protected]:PackageName.jl"
1127+
@test args[1].subdir === nothing
1128+
1129+
api, args, opts = first(Pkg.pkg"add [email protected]:path/to/repo.jl")
1130+
@test api == Pkg.add
1131+
@test length(args) == 1
1132+
@test args[1].url == "[email protected]:path/to/repo.jl"
1133+
@test args[1].subdir === nothing
1134+
end
11201135

11211136
# Test Git URLs with subdir specifiers
11221137
@testset "Git URLs with subdir specifiers" begin

0 commit comments

Comments
 (0)