-
Notifications
You must be signed in to change notification settings - Fork 1
/
gomod.go
108 lines (88 loc) · 2.47 KB
/
gomod.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
package gomod
import (
"strings"
"github.com/pkg/errors"
"github.com/sirkon/goproxy/internal/modfile"
"github.com/sirkon/goproxy/internal/modload"
"github.com/sirkon/goproxy/internal/module"
)
// Replacement is type safe hack to deal with the lack of algebraic/variative typing in Go
type Replacement interface {
notYourConcern()
}
var _ Replacement = Dependency{}
// Dependency describes module and its version
type Dependency struct {
Path string
Version string
}
func (d Dependency) notYourConcern() {}
var _ Replacement = RelativePath("")
// RelativePath describes relative path replacement
type RelativePath string
func (p RelativePath) notYourConcern() {}
// Module go.mod description
type Module struct {
Name string
GoVersion string
Require map[string]string
Exclude map[string]string
Replace map[string]Replacement
}
// Parse parse input Go file
func Parse(fileName string, input []byte) (*Module, error) {
gomod, err := modfile.Parse(fileName, input, fixVersion)
if err != nil {
return nil, err
}
var goVersion string
if gomod.Go != nil {
goVersion = gomod.Go.Version
}
res := &Module{
Name: gomod.Module.Mod.Path,
GoVersion: goVersion,
Require: map[string]string{},
Exclude: map[string]string{},
Replace: map[string]Replacement{},
}
for _, req := range gomod.Require {
res.Require[req.Mod.Path] = req.Mod.Version
}
for _, exc := range gomod.Exclude {
res.Exclude[exc.Mod.Path] = exc.Mod.Version
}
for _, rep := range gomod.Replace {
if len(rep.New.Version) == 0 {
// it is path replacement
res.Replace[rep.Old.Path] = RelativePath(rep.New.Path)
} else {
res.Replace[rep.Old.Path] = Dependency{
Path: rep.New.Path,
Version: rep.New.Version,
}
}
}
return res, nil
}
func fixVersion(path, vers string) (string, error) {
// Special case: remove the old -gopkgin- hack.
if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") {
vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):]
}
// fixVersion is called speculatively on every
// module, version pair from every go.mod file.
// Avoid the query if it looks OK.
_, pathMajor, ok := module.SplitPathVersion(path)
if !ok {
return "", errors.Errorf("malformed module path: %s", path)
}
if vers != "" && module.CanonicalVersion(vers) == vers && module.MatchPathMajor(vers, pathMajor) {
return vers, nil
}
info, err := modload.Query(path, vers, nil)
if err != nil {
return "", err
}
return info.Version, nil
}