2020-02-21 14:21:07 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/xml"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/url"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrNoImport = fmt.Errorf("no git-import found")
|
|
|
|
|
|
|
|
SSHRegex = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_]*\@[A-Za-z][A-Za-z0-9_\.]*\:(?:\/?[A-Za-z][A-Za-z0-9_\-\.]*)*$`)
|
|
|
|
)
|
|
|
|
|
|
|
|
type GitImport struct {
|
2020-09-12 19:53:28 +00:00
|
|
|
Name string
|
|
|
|
HTTP string
|
|
|
|
SSH string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g GitImport) String() string {
|
|
|
|
return fmt.Sprintf("%s %s %s", g.Name, g.HTTP, g.SSH)
|
2020-02-21 14:21:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// charsetReader returns a reader for the given charset.
|
|
|
|
func charsetReader(charset string, input io.Reader) (io.Reader, error) {
|
|
|
|
switch strings.ToLower(charset) {
|
|
|
|
case "ascii":
|
|
|
|
return input, nil
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// parseMetaGoImports returns meta imports from the HTML in r.
|
|
|
|
// Parsing ends at the end of the <head> section or the beginning of the <body>.
|
|
|
|
func parseMetaGitImport(r io.Reader) (gitImport GitImport, err error) {
|
|
|
|
d := xml.NewDecoder(r)
|
|
|
|
d.CharsetReader = charsetReader
|
|
|
|
d.Strict = false
|
|
|
|
var t xml.Token
|
|
|
|
for {
|
|
|
|
t, err = d.RawToken()
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
err = ErrNoImport
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
|
|
|
|
err = ErrNoImport
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
|
|
|
|
err = ErrNoImport
|
|
|
|
break
|
|
|
|
}
|
|
|
|
e, ok := t.(xml.StartElement)
|
|
|
|
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if attrValue(e.Attr, "name") != "git-import" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
content := attrValue(e.Attr, "content")
|
|
|
|
f := strings.Fields(content)
|
|
|
|
if len(f) >= 2 {
|
|
|
|
if _, err = url.Parse(f[1]); err != nil {
|
|
|
|
err = fmt.Errorf("could not parse git-import HTTPS: %v", err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
gitImport = GitImport{
|
2020-09-12 19:53:28 +00:00
|
|
|
Name: f[0],
|
|
|
|
HTTP: f[1],
|
2020-02-21 14:21:07 +00:00
|
|
|
}
|
|
|
|
if len(f) >= 3 {
|
|
|
|
if !SSHRegex.MatchString(f[2]) {
|
|
|
|
err = fmt.Errorf("could not parse git-import SSH: invalid connection string")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
gitImport.SSH = f[2]
|
|
|
|
}
|
|
|
|
err = nil
|
|
|
|
} else {
|
2020-09-12 19:53:28 +00:00
|
|
|
err = fmt.Errorf("incorrect number of import arguments\n\n wanted: project_name cloneHTTP://www.myproject.com/repo [git@myproject.com:repo]\n got: %s", content)
|
2020-02-21 14:21:07 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// attrValue returns the attribute value for the case-insensitive key
|
|
|
|
// `name', or the empty string if nothing is found.
|
|
|
|
func attrValue(attrs []xml.Attr, name string) string {
|
|
|
|
for _, a := range attrs {
|
|
|
|
if strings.EqualFold(a.Name.Local, name) {
|
|
|
|
return a.Value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|