-
Notifications
You must be signed in to change notification settings - Fork 64
/
repo.go
141 lines (124 loc) · 3.81 KB
/
repo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modfetch
import (
"errors"
pathpkg "path"
"sort"
"strings"
"time"
"cmd/go/internal/modfetch/bitbucket"
"cmd/go/internal/modfetch/codehost"
"cmd/go/internal/modfetch/github"
"cmd/go/internal/modfetch/googlesource"
"cmd/go/internal/module"
"cmd/go/internal/semver"
)
// A Repo represents a repository storing all versions of a single module.
type Repo interface {
// ModulePath returns the module path.
ModulePath() string
// Versions lists all known versions with the given prefix.
// Pseudo-versions are not included.
// Versions should be returned sorted in semver order
// (implementations can use SortVersions).
Versions(prefix string) (tags []string, err error)
// Stat returns information about the revision rev.
// A revision can be any identifier known to the underlying service:
// commit hash, branch, tag, and so on.
Stat(rev string) (*RevInfo, error)
// LatestAt returns the latest revision at the given time.
// If branch is non-empty, it restricts the query to revisions
// on the named branch. The meaning of "branch" depends
// on the underlying implementation.
LatestAt(t time.Time, branch string) (*RevInfo, error)
// GoMod returns the go.mod file for the given version.
GoMod(version string) (data []byte, err error)
// Zip downloads a zip file for the given version
// to a new file in a given temporary directory.
// It returns the name of the new file.
// The caller should remove the file when finished with it.
Zip(version, tmpdir string) (tmpfile string, err error)
}
// A Rev describes a single revision in a module repository.
type RevInfo struct {
Version string // version string
Name string // complete ID in underlying repository
Short string // shortened ID, for use in pseudo-version
Time time.Time // commit time
}
// Lookup returns the module with the given module path.
func Lookup(path string) (Repo, error) {
if proxyURL != "" {
return lookupProxy(path)
}
if code, err := lookupCodeHost(path, false); err != errNotHosted {
if err != nil {
return nil, err
}
return newCodeRepo(code, path)
}
return lookupCustomDomain(path)
}
func Import(path string, allowed func(module.Version) bool) (Repo, *RevInfo, error) {
try := func(path string) (Repo, *RevInfo, error) {
r, err := Lookup(path)
if err != nil {
return nil, nil, err
}
info, err := Query(path, "latest", allowed)
if err != nil {
return nil, nil, err
}
_, err = r.GoMod(info.Version)
if err != nil {
return nil, nil, err
}
return r, info, nil
}
var firstErr error
for {
r, info, err := try(path)
if err == nil {
return r, info, nil
}
if firstErr == nil {
firstErr = err
}
p := pathpkg.Dir(path)
if p == "." {
break
}
path = p
}
return nil, nil, firstErr
}
var errNotHosted = errors.New("not hosted")
var isTest bool
func lookupCodeHost(path string, customDomain bool) (codehost.Repo, error) {
switch {
case strings.HasPrefix(path, "github.com/"):
return github.Lookup(path)
case strings.HasPrefix(path, "bitbucket.org/"):
// Special case Bitbucket paths ending in ".git" for backwards compatibility
// with go get.
path = strings.TrimSuffix(path, ".git")
return bitbucket.Lookup(path)
case customDomain && strings.HasSuffix(path[:strings.Index(path, "/")+1], ".googlesource.com/") ||
isTest && strings.HasPrefix(path, "go.googlesource.com/scratch"):
return googlesource.Lookup(path)
case strings.HasPrefix(path, "gopkg.in/"):
return gopkginLookup(path)
}
return nil, errNotHosted
}
func SortVersions(list []string) {
sort.Slice(list, func(i, j int) bool {
cmp := semver.Compare(list[i], list[j])
if cmp != 0 {
return cmp < 0
}
return list[i] < list[j]
})
}