-
Notifications
You must be signed in to change notification settings - Fork 110
/
check.go
128 lines (113 loc) · 2.66 KB
/
check.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
package main
import (
"fmt"
"sort"
gx "github.com/whyrusleeping/gx/gxutil"
"github.com/blang/semver"
)
type pkgImport struct {
parents []string
version semver.Version
}
func check(pkg *gx.Package) (bool, error) {
var failed bool
// name -> hash -> path+version
packages := make(map[string]map[string]*pkgImport)
var traverse func(*gx.Package) error
traverse = func(pkg *gx.Package) error {
return pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error {
pkgVersions, ok := packages[dpkg.Name]
if !ok {
pkgVersions = make(map[string]*pkgImport, 1)
packages[dpkg.Name] = pkgVersions
}
imp, ok := pkgVersions[dep.Hash]
if !ok {
version, err := semver.Parse(dpkg.Version)
if dpkg.Version != "" && err != nil {
fmt.Printf(
"package %s (%s) has an invalid version '%s': %s\n",
dpkg.Name,
dep.Hash,
dpkg.Version,
err,
)
}
pkgVersions[dep.Hash] = &pkgImport{
version: version,
parents: []string{pkg.Name},
}
return traverse(dpkg)
}
imp.parents = append(imp.parents, pkg.Name)
return nil
})
}
if err := traverse(pkg); err != nil {
return !failed, err
}
var dupes []string
for name, pkgVersions := range packages {
switch len(pkgVersions) {
case 0:
panic("must have at least one package version")
case 1:
continue
}
dupes = append(dupes, name)
}
if len(dupes) > 0 {
failed = true
sort.Strings(dupes)
for _, name := range dupes {
pkgVersions := packages[name]
hashes := make([]string, 0, len(pkgVersions))
for h := range pkgVersions {
hashes = append(hashes, h)
}
sort.Slice(hashes, func(i, j int) bool {
ih := hashes[i]
jh := hashes[j]
iv := pkgVersions[ih].version
jv := pkgVersions[jh].version
if res := iv.Compare(jv); res != 0 {
return res < 0
}
return ih < jh
})
fmt.Printf("package %s imported as:\n", name)
for _, hash := range hashes {
imp := pkgVersions[hash]
fmt.Printf(" - %s %s\n", imp.version, hash)
sort.Strings(imp.parents)
for _, p := range imp.parents {
fmt.Printf(" - %s\n", p)
}
}
}
}
// Finally, check names and versions.
if err := pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error {
if dep.Name != dpkg.Name {
failed = true
fmt.Printf(
"dependency %s references a package with name %s\n",
dep.Name,
dpkg.Name,
)
}
if dep.Version != dpkg.Version {
failed = true
fmt.Printf(
"dependency %s has version %s but the referenced package has version %s\n",
dep.Name,
dep.Version,
dpkg.Version,
)
}
return nil
}); err != nil {
return !failed, err
}
return !failed, nil
}