-
Notifications
You must be signed in to change notification settings - Fork 76
/
check_depends.go
155 lines (126 loc) · 3.8 KB
/
check_depends.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"golang.org/x/mod/modfile"
"golang.org/x/tools/go/vcs"
"pault.ag/go/debian/control"
)
type dependency struct {
importPath string
packageName string
// todo version?
}
func execCheckDepends(args []string) {
cwd, err := os.Getwd()
if err != nil {
log.Fatalf("error while getting current directory: %s", err)
}
// Load the already packaged Go modules
golangBinaries, err := getGolangBinaries()
if err != nil {
log.Fatalf("error while getting packaged Go modules: %s", err)
}
// Load the dependencies defined in the Go module (go.mod)
goModDepds, err := parseGoModDependencies(cwd, golangBinaries)
if err != nil {
log.Fatalf("error while parsing go.mod: %s", err)
}
// Load the dependencies defined in the Debian packaging (d/control)
packageDeps, err := parseDebianControlDependencies(cwd)
if err != nil {
log.Fatalf("error while parsing d/control: %s", err)
}
hasChanged := false
// Check for newly introduced dependencies (defined in go.mod but not in d/control)
for _, goModDep := range goModDepds {
found := false
if goModDep.packageName == "" {
fmt.Printf("NEW dependency %s is NOT yet packaged in Debian\n", goModDep.importPath)
continue
}
for _, packageDep := range packageDeps {
if packageDep.packageName == goModDep.packageName {
found = true
break
}
}
if !found {
hasChanged = true
fmt.Printf("NEW dependency %s (%s)\n", goModDep.importPath, goModDep.packageName)
}
}
// Check for now unused dependencies (defined in d/control but not in go.mod)
for _, packageDep := range packageDeps {
found := false
for _, goModDep := range goModDepds {
if goModDep.packageName == packageDep.packageName {
found = true
break
}
}
if !found {
hasChanged = true
fmt.Printf("RM dependency %s (%s)\n", packageDep.importPath, packageDep.packageName)
}
}
if !hasChanged {
fmt.Printf("go.mod and d/control are in sync\n")
}
}
// parseGoModDependencies parse ALL dependencies listed in go.mod
// i.e. it returns the one defined in go.mod as well as the transitively ones
// TODO: this may not be the best way of doing thing since it requires the package to be converted to go module
func parseGoModDependencies(directory string, goBinaries map[string]string) ([]dependency, error) {
b, err := os.ReadFile(filepath.Join(directory, "go.mod"))
if err != nil {
return nil, err
}
modFile, err := modfile.Parse("go.mod", b, nil)
if err != nil {
return nil, err
}
var dependencies []dependency
for _, require := range modFile.Require {
if !require.Indirect {
packageName := ""
// Translate all packages to the root of their repository
rr, err := vcs.RepoRootForImportPath(require.Mod.Path, false)
if err != nil {
log.Printf("Could not determine repo path for import path %q: %v\n", require.Mod.Path, err)
continue
}
if val, exists := goBinaries[rr.Root]; exists {
packageName = val
}
dependencies = append(dependencies, dependency{
importPath: rr.Root,
packageName: packageName,
})
}
}
return dependencies, nil
}
// parseDebianControlDependencies parse the Build-Depends defined in d/control
func parseDebianControlDependencies(directory string) ([]dependency, error) {
ctrl, err := control.ParseControlFile(filepath.Join(directory, "debian", "control"))
if err != nil {
return nil, err
}
var dependencies []dependency
for _, bp := range ctrl.Source.BuildDepends.GetAllPossibilities() {
packageName := strings.Trim(bp.Name, "\n")
// Ignore non -dev dependencies (i.e, debhelper-compat, git, cmake, etc...)
if !strings.HasSuffix(packageName, "-dev") {
continue
}
dependencies = append(dependencies, dependency{
importPath: "", // TODO XS-Go-Import-Path?
packageName: packageName,
})
}
return dependencies, nil
}