-
Notifications
You must be signed in to change notification settings - Fork 416
/
Copy pathapk-installed.go
127 lines (100 loc) · 2.73 KB
/
apk-installed.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
package lockfile
import (
"bufio"
"fmt"
"os"
"sort"
"strings"
)
const AlpineEcosystem Ecosystem = "Alpine"
func groupApkPackageLines(scanner *bufio.Scanner) [][]string {
var groups [][]string
var group []string
for scanner.Scan() {
line := scanner.Text()
if line == "" {
if len(group) > 0 {
groups = append(groups, group)
}
group = make([]string, 0)
continue
}
group = append(group, line)
}
if len(group) > 0 {
groups = append(groups, group)
}
return groups
}
func parseApkPackageGroup(group []string, pathToLockfile string) PackageDetails {
var pkg = PackageDetails{
Ecosystem: AlpineEcosystem,
CompareAs: AlpineEcosystem,
}
// File SPECS: https://wiki.alpinelinux.org/wiki/Apk_spec
for _, line := range group {
switch {
case strings.HasPrefix(line, "P:"):
pkg.Name = strings.TrimPrefix(line, "P:")
case strings.HasPrefix(line, "V:"):
pkg.Version = strings.TrimPrefix(line, "V:")
case strings.HasPrefix(line, "c:"):
pkg.Commit = strings.TrimPrefix(line, "c:")
}
}
if pkg.Version == "" {
pkgPrintName := pkg.Name
if pkgPrintName == "" {
pkgPrintName = "<unknown>"
}
_, _ = fmt.Fprintf(
os.Stderr,
"warning: malformed APK installed file. Found no version number in record. Package %s. File: %s\n",
pkgPrintName,
pathToLockfile,
)
}
return pkg
}
func ParseApkInstalled(pathToLockfile string) ([]PackageDetails, error) {
file, err := os.Open(pathToLockfile)
if err != nil {
return []PackageDetails{}, fmt.Errorf("could not open %s: %w", pathToLockfile, err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
packageGroups := groupApkPackageLines(scanner)
packages := make([]PackageDetails, 0, len(packageGroups))
for _, group := range packageGroups {
pkg := parseApkPackageGroup(group, pathToLockfile)
if pkg.Name == "" {
_, _ = fmt.Fprintf(
os.Stderr,
"warning: malformed APK installed file. Found no package name in record. File: %s\n",
pathToLockfile,
)
continue
}
packages = append(packages, pkg)
}
if err := scanner.Err(); err != nil {
return packages, fmt.Errorf("error while scanning %s: %w", pathToLockfile, err)
}
return packages, nil
}
// FromApkInstalled attempts to parse the given file as an "apk-installed" lockfile
// used by the Alpine Package Keeper (apk) to record installed packages.
func FromApkInstalled(pathToInstalled string) (Lockfile, error) {
packages, err := ParseApkInstalled(pathToInstalled)
sort.Slice(packages, func(i, j int) bool {
if packages[i].Name == packages[j].Name {
return packages[i].Version < packages[j].Version
}
return packages[i].Name < packages[j].Name
})
return Lockfile{
FilePath: pathToInstalled,
ParsedAs: "apk-installed",
Packages: packages,
}, err
}