-
Notifications
You must be signed in to change notification settings - Fork 8
/
parse-go-lock.go
79 lines (62 loc) · 2.04 KB
/
parse-go-lock.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
package lockfile
import (
"fmt"
"os"
"strings"
"golang.org/x/mod/modfile"
)
const GoEcosystem Ecosystem = "Go"
func deduplicatePackages(packages map[string]PackageDetails) map[string]PackageDetails {
details := map[string]PackageDetails{}
for _, detail := range packages {
details[detail.Name+"@"+detail.Version] = detail
}
return details
}
func ParseGoLock(pathToLockfile string) ([]PackageDetails, error) {
lockfileContents, err := os.ReadFile(pathToLockfile)
if err != nil {
return []PackageDetails{}, fmt.Errorf("could not read %s: %w", pathToLockfile, err)
}
parsedLockfile, err := modfile.Parse(pathToLockfile, lockfileContents, nil)
if err != nil {
return []PackageDetails{}, fmt.Errorf("could not parse %s: %w", pathToLockfile, err)
}
packages := map[string]PackageDetails{}
for _, require := range parsedLockfile.Require {
packages[require.Mod.Path+"@"+require.Mod.Version] = PackageDetails{
Name: require.Mod.Path,
Version: strings.TrimPrefix(require.Mod.Version, "v"),
Ecosystem: GoEcosystem,
CompareAs: GoEcosystem,
}
}
for _, replace := range parsedLockfile.Replace {
var replacements []string
if replace.Old.Version == "" {
// If the left version is omitted, all versions of the module are replaced.
for k, pkg := range packages {
if pkg.Name == replace.Old.Path {
replacements = append(replacements, k)
}
}
} else {
// If a version is present on the left side of the arrow (=>),
// only that specific version of the module is replaced
s := replace.Old.Path + "@" + replace.Old.Version
// A `replace` directive has no effect if the module version on the left side is not required.
if _, ok := packages[s]; ok {
replacements = []string{s}
}
}
for _, replacement := range replacements {
packages[replacement] = PackageDetails{
Name: replace.New.Path,
Version: strings.TrimPrefix(replace.New.Version, "v"),
Ecosystem: GoEcosystem,
CompareAs: GoEcosystem,
}
}
}
return pkgDetailsMapToSlice(deduplicatePackages(packages)), nil
}