-
Notifications
You must be signed in to change notification settings - Fork 2
/
npm.go
129 lines (113 loc) · 2.65 KB
/
npm.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
// Package npm implements the npm-specific bits of dependency crawling.
package npm
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"path"
"time"
retryablehttp "github.com/hashicorp/go-retryablehttp"
"github.com/tythe-protocol/tythe/dep"
"github.com/tythe-protocol/tythe/git"
)
type version struct {
Name string `json:"name"`
Repository repository `json:"repository"`
}
type repository struct {
Type string `json:"type"`
URL string `json:"url"`
}
type dist struct {
Shasum string `json:"shasum"`
Tarball string `json:"tarball"`
}
type pkg struct {
Name string `json:"name"`
Dependencies map[string]string `json:"dependencies"`
DevDependencies map[string]string `json:"devDependencies"`
PeerDependencies map[string]string `json:"peerDependencies"`
}
func httpClient(l *log.Logger) *retryablehttp.Client {
c := retryablehttp.NewClient()
c.RetryWaitMax = time.Second
c.RetryMax = 2
c.Logger = l
return c
}
func Dir(name, dataDir string, l *log.Logger) string {
apiURL := fmt.Sprintf("http://registry.npmjs.org/%s/latest", name)
resp, err := httpClient(l).Get(apiURL)
if err != nil {
l.Printf("Could not fetch %s: %s", apiURL, err.Error())
return ""
}
var v version
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&v)
resp.Body.Close()
if err != nil {
l.Printf("Could not decode package.json: %s", err.Error())
return ""
}
if v.Repository.Type != "git" || v.Repository.URL == "" {
return ""
}
// download it
u, err := url.Parse(v.Repository.URL)
if err != nil {
l.Printf("Invalid repo URL: %s", err.Error())
return ""
}
p, err := git.Clone(u, dataDir, l)
if err != nil {
l.Printf("Cannot clone repo: %s", err.Error())
return ""
}
return p
}
type Options struct {
Dependencies bool
DevDependencies bool
PeerDependencies bool
}
func Dependencies(repoPath string, opts Options, l *log.Logger) []dep.ID {
// parse the manifest
pf, err := os.Open(path.Join(repoPath, "package.json"))
if err != nil {
if !os.IsNotExist(err) {
l.Printf("Cannot read package.json: %s", err.Error())
}
return nil
}
defer pf.Close()
var pj pkg
err = json.NewDecoder(pf).Decode(&pj)
if err != nil {
l.Printf("Cannot parse package.json: %s", err.Error())
return nil
}
// return dependencies
depss := []map[string]string{}
if opts.Dependencies {
depss = append(depss, pj.Dependencies)
}
if opts.DevDependencies {
depss = append(depss, pj.DevDependencies)
}
if opts.PeerDependencies {
depss = append(depss, pj.PeerDependencies)
}
var r []dep.ID
for _, deps := range depss {
for d := range deps {
r = append(r, dep.ID{
Type: dep.NPM,
Name: d,
})
}
}
return r
}