-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmodule.go
122 lines (110 loc) · 3.48 KB
/
module.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
package gomods
import (
"fmt"
"net/http"
"os"
"strings"
"github.com/gomods/athens/pkg/download"
"github.com/gomods/athens/pkg/download/addons"
"github.com/gomods/athens/pkg/module"
"github.com/gomods/athens/pkg/paths"
"github.com/gomods/athens/pkg/stash"
"github.com/gomods/athens/pkg/storage"
"github.com/gomods/athens/pkg/storage/fs"
"github.com/spf13/afero"
)
// Module is the struct that keeps a Go module's data
type Module struct {
Name string
Version string
FileExt string
}
// ModuleHandler is the interface that keeps the module handlers for fething and caching
type ModuleHandler interface {
fetch(r *http.Request, c Config) (*storage.Version, error)
storage(c Config) (storage.Backend, error)
dp(fetcher module.Fetcher, s storage.Backend, fs afero.Fs) download.Protocol
}
func (m Module) fetch(r *http.Request, c Config) (download.Protocol, error) {
fetcher, err := module.NewGoGetFetcher(c.GoBinary, nil, c.fs)
if err != nil {
return nil, err
}
s, err := m.storage(c)
if err != nil {
return nil, err
}
dp := m.dp(fetcher, s, c)
return dp, nil
}
func (m Module) storage(c Config) (storage.Backend, error) {
switch c.Cache.Type {
case "local":
// Check if cache storage path exists, if not create it
if _, err := os.Stat(c.Cache.Path); os.IsNotExist(err) {
if err = os.MkdirAll(c.Cache.Path, os.ModePerm); err != nil {
return nil, fmt.Errorf("couldn't create the cache storage directory on %s: %s", c.Cache.Path, err.Error())
}
}
s, err := fs.NewStorage(c.Cache.Path, afero.NewOsFs())
if err != nil {
return nil, fmt.Errorf("could not create new storage from os fs (%s)", err)
}
return s, nil
case "tmp":
s, err := fs.NewStorage(c.Cache.Path, afero.NewOsFs())
if err != nil {
return nil, fmt.Errorf("could not create new storage from os fs (%s)", err)
}
return s, nil
}
return nil, fmt.Errorf("Invalid storage config for gomods")
}
func (m Module) dp(fetcher module.Fetcher, s storage.Backend, c Config) download.Protocol {
lister := module.NewVCSLister(c.GoBinary, nil, c.fs)
st := stash.New(fetcher, s, stash.WithPool(c.Workers), stash.WithSingleflight)
dpOpts := &download.Opts{
Storage: s,
Stasher: st,
Lister: lister,
}
dp := download.New(dpOpts, addons.WithPool(c.Workers))
return dp
}
// ParseImportPath parses the request path and exports the
// module's import path, module's version and file extension
func (m *Module) ParseImportPath(path string) error {
if strings.Contains(path, "@latest") {
pathLatest := strings.Split(path, "/@")
m.Name, m.Version, m.FileExt = pathLatest[0][1:], "", pathLatest[1]
if err := m.DecodeImportPath(); err != nil {
return err
}
return nil
}
// First item in array is modules import path and the secondd item is version+extension
pathSlice := strings.Split(path, "/@v/")
if pathSlice[1] == "list" {
m.Name, m.Version, m.FileExt = pathSlice[0][1:], "", "list"
if err := m.DecodeImportPath(); err != nil {
return err
}
return nil
}
versionExt := modVersionRegex.FindAllStringSubmatch(pathSlice[1], -1)[0]
m.Name, m.Version, m.FileExt = pathSlice[0][1:], versionExt[1], versionExt[2]
if err := m.DecodeImportPath(); err != nil {
return err
}
return nil
}
// DecodeImportPath decodes the module's import path. For more information check
// https://github.com/golang/go/blob/master/src/cmd/go/internal/module/module.go#L375-L433
func (m *Module) DecodeImportPath() error {
decoded, err := paths.DecodePath(m.Name)
if err != nil {
return err
}
m.Name = decoded
return nil
}