提交 96d8bfc6 编写于 作者: J Jingwen Owen Ou

Merge pull request #679 from github/ssh_url_fix

Ignore replacing ssh host that fixes limited network
package git
import (
"bufio"
"os"
"path/filepath"
"regexp"
"strings"
)
const (
hostReStr = "^[ \t]*(Host|HostName|Hostname)[ \t]+(.+)$"
)
type SSHConfig map[string]string
func newSSHConfigReader() *SSHConfigReader {
return &SSHConfigReader{
Files: []string{
filepath.Join(os.Getenv("HOME"), ".ssh/config"),
"/etc/ssh_config",
"/etc/ssh/ssh_config",
},
}
}
type SSHConfigReader struct {
Files []string
}
func (r *SSHConfigReader) Read() SSHConfig {
config := make(SSHConfig)
hostRe := regexp.MustCompile(hostReStr)
for _, filename := range r.Files {
r.readFile(config, hostRe, filename)
}
return config
}
func (r *SSHConfigReader) readFile(c SSHConfig, re *regexp.Regexp, f string) error {
file, err := os.Open(f)
if err != nil {
return err
}
defer file.Close()
hosts := []string{"*"}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
match := re.FindStringSubmatch(line)
if match == nil {
continue
}
names := strings.Fields(match[2])
if match[1] == "Host" {
hosts = names
} else {
for _, host := range hosts {
for _, name := range names {
c[host] = name
}
}
}
}
return scanner.Err()
}
package git
import (
"io/ioutil"
"os"
"testing"
"github.com/bmizerany/assert"
)
func TestSSHConfigReader_Read(t *testing.T) {
f, _ := ioutil.TempFile("", "ssh-config")
c := `Host github.com
Hostname ssh.github.com
Port 443
`
ioutil.WriteFile(f.Name(), []byte(c), os.ModePerm)
r := &SSHConfigReader{[]string{f.Name()}}
sc := r.Read()
assert.Equal(t, "ssh.github.com", sc["github.com"])
}
package git package git
import ( import (
"bufio"
"net/url" "net/url"
"os"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
) )
var ( var (
ProtocolRe = regexp.MustCompile("^[a-zA-Z_-]+://") cachedSSHConfig SSHConfig
SshConfigFiles = []string{ protocolRe = regexp.MustCompile("^[a-zA-Z_-]+://")
filepath.Join(os.Getenv("HOME"), ".ssh/config"),
"/etc/ssh_config",
"/etc/ssh/ssh_config",
}
SshConfig map[string]string
) )
func ParseURL(rawurl string) (u *url.URL, err error) { type URLParser struct {
if !ProtocolRe.MatchString(rawurl) && strings.Contains(rawurl, ":") { SSHConfig SSHConfig
rawurl = "ssh://" + strings.Replace(rawurl, ":", "/", 1) }
func (p *URLParser) Parse(rawURL string) (u *url.URL, err error) {
if !protocolRe.MatchString(rawURL) && strings.Contains(rawURL, ":") {
rawURL = "ssh://" + strings.Replace(rawURL, ":", "/", 1)
}
u, err = url.Parse(rawURL)
if err != nil {
return
} }
u, err = url.Parse(rawurl) sshHost := p.SSHConfig[u.Host]
if err == nil { // ignore replacing host that fixes for limited network
if SshConfig == nil { // https://help.github.com/articles/using-ssh-over-the-https-port
SshConfig = readSshConfig() ignoredHost := u.Host == "github.com" && sshHost == "ssh.github.com"
} if !ignoredHost && sshHost != "" {
if SshConfig[u.Host] != "" { u.Host = sshHost
u.Host = SshConfig[u.Host]
}
} }
return return
} }
func readSshConfig() map[string]string { func ParseURL(rawURL string) (u *url.URL, err error) {
config := make(map[string]string) if cachedSSHConfig == nil {
hostRe := regexp.MustCompile("^[ \t]*(Host|HostName)[ \t]+(.+)$") cachedSSHConfig = newSSHConfigReader().Read()
for _, filename := range SshConfigFiles {
file, err := os.Open(filename)
if err != nil {
continue
}
hosts := []string{"*"}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
match := hostRe.FindStringSubmatch(line)
if match == nil {
continue
}
names := strings.Fields(match[2])
if match[1] == "Host" {
hosts = names
} else {
for _, host := range hosts {
for _, name := range names {
config[host] = name
}
}
}
}
file.Close()
} }
return config p := &URLParser{cachedSSHConfig}
return p.Parse(rawURL)
} }
package git package git
import ( import (
"github.com/bmizerany/assert"
"testing" "testing"
"github.com/bmizerany/assert"
) )
func TestURL_ParseURL(t *testing.T) { func TestURLParser_ParseURL(t *testing.T) {
u, err := ParseURL("https://github.com/octokit/go-octokit.git") c := make(SSHConfig)
c["github.com"] = "ssh.github.com"
c["git.company.com"] = "ssh.git.company.com"
p := &URLParser{c}
u, err := p.Parse("https://github.com/octokit/go-octokit.git")
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
assert.Equal(t, "github.com", u.Host) assert.Equal(t, "github.com", u.Host)
assert.Equal(t, "https", u.Scheme) assert.Equal(t, "https", u.Scheme)
assert.Equal(t, "/octokit/go-octokit.git", u.Path) assert.Equal(t, "/octokit/go-octokit.git", u.Path)
u, err = ParseURL("git://github.com/octokit/go-octokit.git") u, err = p.Parse("git://github.com/octokit/go-octokit.git")
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
assert.Equal(t, "github.com", u.Host) assert.Equal(t, "github.com", u.Host)
assert.Equal(t, "git", u.Scheme) assert.Equal(t, "git", u.Scheme)
assert.Equal(t, "/octokit/go-octokit.git", u.Path) assert.Equal(t, "/octokit/go-octokit.git", u.Path)
u, err = ParseURL("git@github.com:lostisland/go-sawyer.git") u, err = p.Parse("git@github.com:lostisland/go-sawyer.git")
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
assert.Equal(t, "github.com", u.Host) assert.Equal(t, "github.com", u.Host)
assert.Equal(t, "ssh", u.Scheme) assert.Equal(t, "ssh", u.Scheme)
assert.Equal(t, "git", u.User.Username()) assert.Equal(t, "git", u.User.Username())
assert.Equal(t, "/lostisland/go-sawyer.git", u.Path) assert.Equal(t, "/lostisland/go-sawyer.git", u.Path)
u, err = p.Parse("https://git.company.com/octokit/go-octokit.git")
assert.Equal(t, nil, err)
assert.Equal(t, "ssh.git.company.com", u.Host)
assert.Equal(t, "https", u.Scheme)
assert.Equal(t, "/octokit/go-octokit.git", u.Path)
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册