Skip to content

Commit 63138cb

Browse files
committed
cmd/go/internal/modfetch/github: fetch from github
1 parent 3a8c085 commit 63138cb

File tree

1 file changed

+318
-0
lines changed
  • vendor/cmd/go/internal/modfetch/github

1 file changed

+318
-0
lines changed

Diff for: vendor/cmd/go/internal/modfetch/github/fetch.go

+318
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package github
6+
7+
import (
8+
"fmt"
9+
"io"
10+
"net/http"
11+
"net/url"
12+
"strings"
13+
"time"
14+
15+
"cmd/go/internal/modfetch/codehost"
16+
web "cmd/go/internal/web2"
17+
)
18+
19+
func Lookup(path string) (codehost.Repo, error) {
20+
f := strings.Split(path, "/")
21+
if len(f) < 3 || f[0] != "github.com" {
22+
return nil, fmt.Errorf("github repo must be github.com/org/project")
23+
}
24+
25+
// Check for moved, renamed, or incorrect case in repository.
26+
// Otherwise the API calls all appear to work.
27+
// We need to do better here, but it's unclear exactly what.
28+
var data struct {
29+
FullName string `json:"full_name"`
30+
}
31+
err := web.Get("https://api.github.com/repos/"+url.PathEscape(f[1])+"/"+url.PathEscape(f[2]), web.DecodeJSON(&data))
32+
if err != nil {
33+
return nil, err
34+
}
35+
myFullName := f[1] + "/" + f[2]
36+
if myFullName != data.FullName {
37+
why := "moved"
38+
if strings.EqualFold(myFullName, data.FullName) {
39+
why = "wrong case"
40+
}
41+
return nil, fmt.Errorf("module path of repo is github.com/%s, not %s (%s)", data.FullName, path, why)
42+
}
43+
44+
return newRepo(f[1], f[2]), nil
45+
}
46+
47+
func newRepo(owner, repository string) codehost.Repo {
48+
return &repo{owner, repository}
49+
}
50+
51+
type repo struct {
52+
owner string
53+
repo string
54+
}
55+
56+
func (r *repo) Root() string {
57+
return "github.com/" + r.owner + "/" + r.repo
58+
}
59+
60+
func (r *repo) Tags(prefix string) ([]string, error) {
61+
var tags []string
62+
u := "https://api.github.com/repos/" + url.PathEscape(r.owner) + "/" + url.PathEscape(r.repo) + "/tags"
63+
for u != "" {
64+
var data []struct {
65+
Name string
66+
}
67+
var hdr http.Header
68+
err := web.Get(u, web.Header(&hdr), web.DecodeJSON(&data))
69+
if err != nil {
70+
return nil, err
71+
}
72+
for _, t := range data {
73+
if strings.HasPrefix(t.Name, prefix) {
74+
tags = append(tags, t.Name)
75+
}
76+
}
77+
last := u
78+
u = ""
79+
for _, link := range parseLinks(hdr.Get("Link")) {
80+
if link.Rel == "next" && link.URL != last {
81+
u = link.URL
82+
}
83+
}
84+
}
85+
return tags, nil
86+
}
87+
88+
func (r *repo) LatestAt(t time.Time, branch string) (*codehost.RevInfo, error) {
89+
var commits []struct {
90+
SHA string
91+
Commit struct {
92+
Committer struct {
93+
Date string
94+
}
95+
}
96+
}
97+
err := web.Get(
98+
"https://api.github.com/repos/"+url.PathEscape(r.owner)+"/"+url.PathEscape(r.repo)+"/commits?sha="+url.QueryEscape(branch)+"&until="+url.QueryEscape(t.UTC().Format("2006-01-02T15:04:05Z"))+"&per_page=2",
99+
web.DecodeJSON(&commits),
100+
)
101+
if err != nil {
102+
return nil, err
103+
}
104+
if len(commits) == 0 {
105+
return nil, fmt.Errorf("no commits")
106+
}
107+
d, err := time.Parse("2006-01-02T15:04:05Z", commits[0].Commit.Committer.Date)
108+
if err != nil {
109+
return nil, err
110+
}
111+
112+
info := &codehost.RevInfo{
113+
Name: commits[0].SHA,
114+
Short: codehost.ShortenSHA1(commits[0].SHA),
115+
Time: d,
116+
}
117+
return info, nil
118+
}
119+
120+
func (r *repo) Stat(rev string) (*codehost.RevInfo, error) {
121+
var tag string
122+
if !codehost.AllHex(rev) {
123+
// Resolve tag to rev
124+
tag = rev
125+
var ref struct {
126+
Ref string
127+
Object struct {
128+
Type string
129+
SHA string
130+
URL string
131+
}
132+
}
133+
err := web.Get(
134+
"https://api.github.com/repos/"+url.PathEscape(r.owner)+"/"+url.PathEscape(r.repo)+"/git/refs/tags/"+tag,
135+
web.DecodeJSON(&ref),
136+
)
137+
if err != nil {
138+
return nil, err
139+
}
140+
switch ref.Object.Type {
141+
default:
142+
return nil, fmt.Errorf("invalid tag %q: not a commit or tag (%q)", tag, ref.Object.Type)
143+
144+
case "commit":
145+
rev = ref.Object.SHA
146+
147+
case "tag":
148+
var info struct {
149+
Object struct {
150+
SHA string
151+
Type string
152+
}
153+
}
154+
err = web.Get(
155+
ref.Object.URL,
156+
web.DecodeJSON(&info),
157+
)
158+
if err != nil {
159+
return nil, err
160+
}
161+
if info.Object.Type != "commit" {
162+
return nil, fmt.Errorf("invalid annotated tag %q: not a commit (%q)", tag, info.Object.Type)
163+
}
164+
rev = info.Object.SHA
165+
}
166+
if rev == "" {
167+
return nil, fmt.Errorf("invalid tag %q: missing SHA in GitHub response", tag)
168+
}
169+
}
170+
171+
var commits []struct {
172+
SHA string
173+
Commit struct {
174+
Committer struct {
175+
Date string
176+
}
177+
}
178+
}
179+
err := web.Get(
180+
"https://api.github.com/repos/"+url.PathEscape(r.owner)+"/"+url.PathEscape(r.repo)+"/commits?sha="+url.QueryEscape(rev)+"&per_page=2",
181+
web.DecodeJSON(&commits),
182+
)
183+
if err != nil {
184+
return nil, err
185+
}
186+
if len(commits) == 0 {
187+
return nil, fmt.Errorf("no commits")
188+
}
189+
if !strings.HasPrefix(commits[0].SHA, rev) {
190+
return nil, fmt.Errorf("wrong rev returned by server")
191+
}
192+
d, err := time.Parse("2006-01-02T15:04:05Z", commits[0].Commit.Committer.Date)
193+
if err != nil {
194+
return nil, err
195+
}
196+
info := &codehost.RevInfo{
197+
Name: commits[0].SHA,
198+
Short: codehost.ShortenSHA1(commits[0].SHA),
199+
Version: tag,
200+
Time: d,
201+
}
202+
return info, nil
203+
}
204+
205+
func (r *repo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
206+
var meta struct {
207+
Type string
208+
Size int64
209+
Name string
210+
DownloadURL string `json:"download_url"`
211+
}
212+
err := web.Get(
213+
"https://api.github.com/repos/"+url.PathEscape(r.owner)+"/"+url.PathEscape(r.repo)+"/contents/"+url.PathEscape(file)+"?ref="+url.QueryEscape(rev),
214+
web.DecodeJSON(&meta),
215+
)
216+
if err != nil {
217+
return nil, err
218+
}
219+
if meta.DownloadURL == "" {
220+
return nil, fmt.Errorf("no download URL")
221+
}
222+
223+
// TODO: Use maxSize.
224+
var body []byte
225+
err = web.Get(meta.DownloadURL, web.ReadAllBody(&body))
226+
if err != nil {
227+
return nil, err
228+
}
229+
return body, nil
230+
}
231+
232+
func (r *repo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) {
233+
// TODO: Make web.Get copy to file for us, with limit.
234+
var body io.ReadCloser
235+
err = web.Get(
236+
"https://api.github.com/repos/"+url.PathEscape(r.owner)+"/"+url.PathEscape(r.repo)+"/zipball/"+url.PathEscape(rev),
237+
web.Body(&body),
238+
)
239+
if err != nil {
240+
if body != nil {
241+
body.Close()
242+
}
243+
return nil, "", err
244+
}
245+
return body, "", nil
246+
}
247+
248+
type link struct {
249+
URL string
250+
Rel string
251+
}
252+
253+
func parseLinks(text string) []link {
254+
var links []link
255+
for text != "" {
256+
text = strings.TrimSpace(text)
257+
if !strings.HasPrefix(text, "<") {
258+
break
259+
}
260+
i := strings.Index(text, ">")
261+
if i < 0 {
262+
break
263+
}
264+
u := text[1:i]
265+
text = strings.TrimSpace(text[i+1:])
266+
Attrs:
267+
for strings.HasPrefix(text, ";") {
268+
text = text[1:]
269+
j := 0
270+
for j < len(text) && text[j] != '=' {
271+
if text[j] == ',' || text[j] == ';' || text[j] == '"' {
272+
break Attrs
273+
}
274+
j++
275+
}
276+
if j >= len(text) {
277+
break Attrs
278+
}
279+
key := strings.TrimSpace(text[:j])
280+
text = strings.TrimSpace(text[j+1:])
281+
var val string
282+
if len(text) > 0 && text[0] == '"' {
283+
k := 1
284+
for k < len(text) && text[k] != '"' {
285+
if text[k] == '\\' && k+1 < len(text) {
286+
k++
287+
}
288+
k++
289+
}
290+
if k >= len(text) {
291+
break Attrs
292+
}
293+
val, text = text[1:k], text[k+1:]
294+
} else {
295+
k := 0
296+
for k < len(text) && text[k] != ';' && text[k] != ',' {
297+
if text[k] == '"' {
298+
break Attrs
299+
}
300+
k++
301+
}
302+
if k >= len(text) {
303+
break Attrs
304+
}
305+
val, text = text[:k], text[k:]
306+
}
307+
if key == "rel" {
308+
links = append(links, link{URL: u, Rel: strings.TrimSpace(val)})
309+
}
310+
}
311+
text = strings.TrimSpace(text)
312+
if !strings.HasPrefix(text, ",") {
313+
break
314+
}
315+
text = text[1:]
316+
}
317+
return links
318+
}

0 commit comments

Comments
 (0)