-
Notifications
You must be signed in to change notification settings - Fork 2
/
merge.go
121 lines (100 loc) · 3.06 KB
/
merge.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
package jarindex
import (
jipb "github.com/stackb/scala-gazelle/build/stack/gazelle/scala/jarindex"
)
const (
debugDuplicateClasses = false
debugSplitPackages = true
)
type warnFunc func(format string, args ...interface{})
func MergeJarFiles(warn warnFunc, predefined []string, jarFiles []*jipb.JarFile) (*jipb.JarIndex, error) {
var index jipb.JarIndex
// jarLabels is used to prevent duplicate entries for a given jar.
labels := make(map[string]bool)
// labelsByPackage is used to detect split labelsByPackage
labelsByPackage := make(map[string][]string)
// providersByClass is used to check if more than one label provides a given
// class.
providersByClass := make(map[string]*jipb.ClassFileProvider)
// predefinedLabels do not need to be resolved
predefinedLabels := make(map[string]struct{})
for _, l := range predefined {
predefinedLabels[l] = struct{}{}
}
// predefinedSymbols is the set of symbols we can remove from each class
// files' list of symbols; these will never need to be resolved.
predefinedSymbols := map[string]struct{}{
"java.lang.Object": {},
}
for _, jar := range jarFiles {
if labels[jar.Label] {
warn("duplicate jar label: %s", jar.Label)
continue
}
labels[jar.Label] = true
visitJarFile(warn, jar, labelsByPackage, predefinedLabels, predefinedSymbols, providersByClass)
index.JarFile = append(index.JarFile, jar)
}
// remove predefined symbols
for _, jar := range index.JarFile {
for _, file := range jar.ClassFile {
var resolvable []string
for _, sym := range file.Symbols {
if _, ok := predefinedSymbols[sym]; ok {
continue
}
resolvable = append(resolvable, sym)
}
file.Symbols = resolvable
}
}
if debugDuplicateClasses {
for classname, providers := range providersByClass {
if len(providers.Label) > 1 {
warn("class is provided by more than one label: %s: %v", classname, providers.Label)
}
}
}
if debugSplitPackages {
for pkg, labels := range labelsByPackage {
if len(labels) > 1 {
warn("split-package! %q is provided by more than one label: %v", pkg, labels)
}
}
}
return &index, nil
}
func visitJarFile(
warn warnFunc,
jar *jipb.JarFile,
packages map[string][]string,
predefinedLabels, predefinedSymbols map[string]struct{},
providersByClass map[string]*jipb.ClassFileProvider,
) {
if jar.Label == "" {
warn("missing jar label: %s", jar.Filename)
return
}
if jar.Filename == "" {
warn("missing jar filename: %s", jar.Label)
return
}
// log.Println("---", jar.Label, "---")
if _, ok := predefinedLabels[jar.Label]; ok {
// TODO: consider only recording packages, not classes
for _, file := range jar.ClassFile {
predefinedSymbols[file.Name] = struct{}{}
}
}
for _, pkg := range jar.PackageName {
packages[pkg] = append(packages[pkg], jar.Label)
}
for _, classFile := range jar.ClassFile {
providers, found := providersByClass[classFile.Name]
if !found {
providers = &jipb.ClassFileProvider{Class: classFile.Name}
providersByClass[classFile.Name] = providers
}
providers.Label = append(providers.Label, jar.Label)
}
}