Improved SSH support: non-bare urls, custom ports, and GIT_SSH/plink#404
Improved SSH support: non-bare urls, custom ports, and GIT_SSH/plink#404technoweenie merged 2 commits intogit-lfs:masterfrom
Conversation
|
Can you merge the latest master now that #403 has been merged? Rebase if you like. |
lfs/config.go
Outdated
There was a problem hiding this comment.
I'm not a fan of this giant method. I'd prefer to have something that calls internal functions:
endpoint := Endpoint{Url: urlstr}
u, err := url.Parse(urlstr)
if err != nil {
// right now just {user}@{host}:{path}, but maybe others one day?
processSshRemote(urlstr)
}
switch u.Scheme {
case "http", "https": processHttpUrl(u)
case "ssh": processSshUrl(u)
default: endpoint.Url = ENDPOINT_URL_UNKNOWN
}Note: feel free to override my suggestions on method or variable names.
Minor nitpick: I tend to use rawurl. I don't like having type related suffixes on variable names. Maybe it's from my experience using hungarian notation in VB/Access code :)
There was a problem hiding this comment.
OK - rebased and will refactor a little in next commit.
You did VB/Access too eh? We should commiserate over a beer one day ;)
lfs/config.go
Outdated
There was a problem hiding this comment.
I'd prefer early returns.
if u.Scheme != "" || u.Path == "" {
return u
}
// This might be a bare SSH URL
// Turn it into ssh:// for simplicity of extraction later
parts := strings.Split(u.Path, ":")
if len(parts) < 2 {
return u
}
// Treat presence of ':' as a bare URL
var newPath string
if len(parts) > 2 { // port included; really should only ever be 3 parts
newPath = fmt.Sprintf("%v:%v", parts[0], strings.Join(parts[1:], "/"))
} else {
newPath = strings.Join(parts, "/")
}
newrawurl := fmt.Sprintf("ssh://%v", newPath)
newu, err := url.Parse(newrawurl)
if err != nil {
return u
}
return newuThere was a problem hiding this comment.
Another possibility is a switch statement:
var newPath string
switch {
case len(parts) < 2:
return u
case len(parts) == 2:
newPath = strings.Join(parts, "/")
default:
// port included; really should only ever be 3 parts
newPath = fmt.Sprintf("%v:%v", parts[0], strings.Join(parts[1:], "/"))
}There was a problem hiding this comment.
I definitely prefer early returns vs multiple levels of nesting. 👍
|
Without this change, you can not use SSH-connections multiplexing on Windows. |
|
This PR doesn't look ready, so it likely won't make it in. We can release v0.5.3 whenever we want though. |
|
AFAIK the only thing that's "not ready" about it is stylistic preferences? |
|
Yes, and a merge conflict with master. |
|
OK, that must be new in the last day or two. Will come back to this next week. |
|
Are we doing ssh multiplexing in this PR? If so, has it been benchmarked with large numbers of large files? It is my understanding that ssh multiplexing starts to fall over when connections with large amounts of data are involved, though I am admittedly unfamiliar with plink. |
|
There's also another patch I'm holding back because of insufficient testing. We can roll v0.5.3 when these two are ready. I'm anxious to get v0.5.2 out because it's been way too long since the last release. @rubyist: We may be able to punt on that concern for now until we're reviewing the SSH API. |
All this PR does is support ssh:// url forms, custom ports, and the GIT_SSH env var. Its performance characteristics are identical to master since the ssh calls themselves happen exactly the same way, all it does is support cases that would previously fail. My other PR on full SSH support opens only Config.ConcurrentTransfers() SSH connections to run the API over and pipes everything through those. |
|
@sinbad 👍 that sounds OK then. My concerns were around using something like ssh's ControlMaster (or equivalents in plink, etc), using ConcurrentTransfers() connections with the transfer queue should be just fine. |
Yeah I did consider adding another config parameter that could override ConcurrentTransfers() for SSH connections, using a default lower limit but for simplicity I didn't, and the default 3 should be OK for all but the most totalitarian server admin. |
I make little benchmark on Windows/Linux with our project repository #376 (4231 LFS files, working copy size: 3.6G, original repository size: ~50G). Local gigabit network environment. On Linux: This changes enable using single SSH connection for all On Windows: A similar function is in Putty (plink.exe), but its use needs support GIT_SSH environment variable (this PR). The effect of multiplex under Windows, I did not measure. |
* Full SSH urls e.g. ssh://user@host/repo * Custom ports in both bare and full urls * GIT_SSH environment for alternate ssh clients * Explicit support for plink.exe and TortoisePlink.exe
|
Rebased on master & added early-outs, should be ready for inclusion in 0.5.3 now. |
lfs/endpoint.go
Outdated
There was a problem hiding this comment.
Should we really return an empty Endpoint in case of err != nil? Why not Endpoint{Url: rawurl}?
There was a problem hiding this comment.
Pretty much anything will go through the default: route, but for consistency with the other routes I've returned EndpointUrlUnknown in that case. You have to throw something pretty whacky at url.Parse for it to return an error (none of the tests with bare strings manage it).
…t EndpointUrlUnknown
Refactor some of the code in #404
Backport #404 for v0.5.x: Improved SSH support: non-bare urls, custom ports, and GIT_SSH/plink
Depends on #403 (included in PR)