github.com/x-motemen/ghq@v1.6.1/go_import.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "net/http" 7 "net/url" 8 "strings" 9 10 "golang.org/x/net/html" 11 ) 12 13 // metaImport represents the parsed <meta name="go-import" 14 // content="prefix vcs reporoot" /> tags from HTML files. 15 type metaImport struct { 16 Prefix, VCS, RepoRoot string 17 } 18 19 func detectGoImport(u *url.URL) (string, *url.URL, error) { 20 goGetU := *u 21 q := goGetU.Query() 22 q.Add("go-get", "1") 23 goGetU.RawQuery = q.Encode() 24 25 cli := &http.Client{ 26 CheckRedirect: func(req *http.Request, via []*http.Request) error { 27 // never follow redirection 28 return http.ErrUseLastResponse 29 }, 30 } 31 req, _ := http.NewRequest(http.MethodGet, goGetU.String(), nil) 32 req.Header.Add("User-Agent", fmt.Sprintf("ghq/%s (+https://github.com/motemen/ghq)", version)) 33 resp, err := cli.Do(req) 34 if err != nil { 35 return "", nil, err 36 } 37 defer resp.Body.Close() 38 39 return detectVCSAndRepoURL(resp.Body) 40 } 41 42 // find meta tag like following from html 43 // <meta name="go-import" content="gopkg.in/yaml.v2 git https://gopkg.in/yaml.v2"> 44 // ref. https://golang.org/cmd/go/#hdr-Remote_import_paths 45 func detectVCSAndRepoURL(r io.Reader) (string, *url.URL, error) { 46 doc, err := html.Parse(r) 47 if err != nil { 48 return "", nil, err 49 } 50 51 var mImport *metaImport 52 53 var f func(*html.Node) 54 f = func(n *html.Node) { 55 if mImport != nil { 56 return 57 } 58 if n.Type == html.ElementNode && n.Data == "meta" { 59 var ( 60 goImportMeta = false 61 content = "" 62 ) 63 for _, a := range n.Attr { 64 if a.Key == "name" && a.Val == "go-import" { 65 goImportMeta = true 66 continue 67 } 68 if a.Key == "content" { 69 content = a.Val 70 } 71 } 72 if f := strings.Fields(content); goImportMeta && len(f) == 3 && f[1] != "mod" { 73 mImport = &metaImport{ 74 Prefix: f[0], 75 VCS: f[1], 76 RepoRoot: f[2], 77 } 78 } 79 } 80 for c := n.FirstChild; c != nil; c = c.NextSibling { 81 f(c) 82 } 83 } 84 f(doc) 85 86 if mImport == nil { 87 return "", nil, fmt.Errorf("no go-import meta tags detected") 88 } 89 u, err := url.Parse(mImport.RepoRoot) 90 if err != nil { 91 return "", nil, err 92 } 93 return mImport.VCS, u, nil 94 }