blob: bb4b9fdd9cd6dbe7774cf91b2acaa69351d3dbd9 [file] [log] [blame]
Dan Willemsen01f0a052019-02-05 13:44:20 -08001// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// This is a script that can be used to analyze the results from
16// build/soong/build_test.bash and recommend what devices need changes to their
17// BUILD_BROKEN_* flags.
18//
19// To use, download the logs.zip from one or more branches, and extract them
20// into subdirectories of the current directory. So for example, I have:
21//
Colin Crossd079e0b2022-08-16 10:27:33 -070022// ./aosp-master/aosp_arm/std_full.log
23// ./aosp-master/aosp_arm64/std_full.log
24// ./aosp-master/...
25// ./internal-master/aosp_arm/std_full.log
26// ./internal-master/aosp_arm64/std_full.log
27// ./internal-master/...
Dan Willemsen01f0a052019-02-05 13:44:20 -080028//
29// Then I use `go run path/to/build_broken_logs.go *`
30package main
31
32import (
33 "fmt"
34 "io/ioutil"
35 "log"
36 "os"
37 "path/filepath"
38 "sort"
39 "strings"
40)
41
42func main() {
43 for _, branch := range os.Args[1:] {
44 fmt.Printf("\nBranch %s:\n", branch)
45 PrintResults(ParseBranch(branch))
46 }
47}
48
49type BuildBrokenBehavior int
50
51const (
52 DefaultFalse BuildBrokenBehavior = iota
53 DefaultTrue
54 DefaultDeprecated
55)
56
Dan Willemsen9dfaa062020-01-29 10:09:16 -080057type Setting struct {
Dan Willemsen01f0a052019-02-05 13:44:20 -080058 name string
59 behavior BuildBrokenBehavior
60 warnings []string
Dan Willemsen9dfaa062020-01-29 10:09:16 -080061}
62
63var buildBrokenSettings = []Setting{
Dan Willemsen01f0a052019-02-05 13:44:20 -080064 {
Dan Willemsen01f0a052019-02-05 13:44:20 -080065 name: "BUILD_BROKEN_DUP_RULES",
66 behavior: DefaultFalse,
67 warnings: []string{"overriding commands for target"},
68 },
69 {
Dan Willemsen25e6f092019-04-09 10:22:43 -070070 name: "BUILD_BROKEN_USES_NETWORK",
71 behavior: DefaultDeprecated,
72 },
Dan Willemsen9dfaa062020-01-29 10:09:16 -080073 {
74 name: "BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
75 behavior: DefaultTrue,
76 warnings: []string{
77 "COPY_HEADERS has been deprecated",
78 "COPY_HEADERS is deprecated",
79 },
80 },
81}
82
83type Branch struct {
84 Settings []Setting
85 Logs []ProductLog
Dan Willemsen01f0a052019-02-05 13:44:20 -080086}
87
88type ProductBranch struct {
89 Branch string
90 Name string
91}
92
93type ProductLog struct {
94 ProductBranch
95 Log
96 Device string
97}
98
99type Log struct {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800100 WarningModuleTypes []string
101 ErrorModuleTypes []string
102
103 BuildBroken map[string]*bool
104 HasBroken map[string]int
Dan Willemsen01f0a052019-02-05 13:44:20 -0800105}
106
107func Merge(l, l2 Log) Log {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800108 if l.BuildBroken == nil {
109 l.BuildBroken = map[string]*bool{}
Dan Willemsen01f0a052019-02-05 13:44:20 -0800110 }
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800111 if l.HasBroken == nil {
112 l.HasBroken = map[string]int{}
Dan Willemsen01f0a052019-02-05 13:44:20 -0800113 }
114
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800115 for n, v := range l.BuildBroken {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800116 if v == nil {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800117 l.BuildBroken[n] = l2.BuildBroken[n]
Dan Willemsen01f0a052019-02-05 13:44:20 -0800118 }
119 }
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800120 for n, v := range l2.BuildBroken {
121 if _, ok := l.BuildBroken[n]; !ok {
122 l.BuildBroken[n] = v
123 }
124 }
125
126 for n := range l.HasBroken {
127 if l.HasBroken[n] < l2.HasBroken[n] {
128 l.HasBroken[n] = l2.HasBroken[n]
129 }
130 }
131 for n := range l2.HasBroken {
132 if _, ok := l.HasBroken[n]; !ok {
133 l.HasBroken[n] = l2.HasBroken[n]
134 }
Dan Willemsen01f0a052019-02-05 13:44:20 -0800135 }
136
137 return l
138}
139
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800140func PrintResults(branch Branch) {
141 products := branch.Logs
Dan Willemsen01f0a052019-02-05 13:44:20 -0800142 devices := map[string]Log{}
143 deviceNames := []string{}
144
145 for _, product := range products {
146 device := product.Device
147 if _, ok := devices[device]; !ok {
148 deviceNames = append(deviceNames, device)
149 }
150 devices[device] = Merge(devices[device], product.Log)
151 }
152
153 sort.Strings(deviceNames)
154
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800155 for _, setting := range branch.Settings {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800156 printed := false
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800157 n := setting.name
Dan Willemsen01f0a052019-02-05 13:44:20 -0800158
159 for _, device := range deviceNames {
160 log := devices[device]
161
162 if setting.behavior == DefaultTrue {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800163 if log.BuildBroken[n] == nil || *log.BuildBroken[n] == false {
164 if log.HasBroken[n] > 0 {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800165 printed = true
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800166 plural := ""
167 if log.HasBroken[n] > 1 {
168 plural = "s"
169 }
170 fmt.Printf(" %s needs to set %s := true (%d instance%s)\n", device, setting.name, log.HasBroken[n], plural)
Dan Willemsen01f0a052019-02-05 13:44:20 -0800171 }
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800172 } else if log.HasBroken[n] == 0 {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800173 printed = true
174 fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
175 }
176 } else if setting.behavior == DefaultFalse {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800177 if log.BuildBroken[n] == nil {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800178 // Nothing to be done
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800179 } else if *log.BuildBroken[n] == false {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800180 printed = true
181 fmt.Printf(" %s sets %s := false, which is the default and can be removed\n", device, setting.name)
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800182 } else if log.HasBroken[n] == 0 {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800183 printed = true
184 fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
185 }
186 } else if setting.behavior == DefaultDeprecated {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800187 if log.BuildBroken[n] != nil {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800188 printed = true
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800189 if log.HasBroken[n] > 0 {
190 plural := ""
191 if log.HasBroken[n] > 1 {
192 plural = "s"
193 }
194 fmt.Printf(" %s sets %s := %v, which is deprecated, but has %d failure%s\n", device, setting.name, *log.BuildBroken[n], log.HasBroken[n], plural)
Dan Willemsen01f0a052019-02-05 13:44:20 -0800195 } else {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800196 fmt.Printf(" %s sets %s := %v, which is deprecated and can be removed\n", device, setting.name, *log.BuildBroken[n])
Dan Willemsen01f0a052019-02-05 13:44:20 -0800197 }
198 }
199 }
200 }
201
202 if printed {
203 fmt.Println()
204 }
205 }
206}
207
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800208func ParseBranch(name string) Branch {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800209 products, err := filepath.Glob(filepath.Join(name, "*"))
210 if err != nil {
211 log.Fatal(err)
212 }
213
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800214 ret := Branch{Logs: []ProductLog{}}
Dan Willemsen01f0a052019-02-05 13:44:20 -0800215 for _, product := range products {
216 product = filepath.Base(product)
217
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800218 ret.Logs = append(ret.Logs, ParseProduct(ProductBranch{Branch: name, Name: product}))
219 }
220
221 ret.Settings = append(ret.Settings, buildBrokenSettings...)
222 if len(ret.Logs) > 0 {
223 for _, mtype := range ret.Logs[0].WarningModuleTypes {
224 if mtype == "BUILD_COPY_HEADERS" || mtype == "" {
225 continue
226 }
227 ret.Settings = append(ret.Settings, Setting{
228 name: "BUILD_BROKEN_USES_" + mtype,
229 behavior: DefaultTrue,
230 warnings: []string{mtype + " has been deprecated"},
231 })
232 }
233 for _, mtype := range ret.Logs[0].ErrorModuleTypes {
234 if mtype == "BUILD_COPY_HEADERS" || mtype == "" {
235 continue
236 }
237 ret.Settings = append(ret.Settings, Setting{
238 name: "BUILD_BROKEN_USES_" + mtype,
239 behavior: DefaultFalse,
240 warnings: []string{mtype + " has been deprecated"},
241 })
242 }
243 }
244
245 for _, productLog := range ret.Logs {
246 ScanProduct(ret.Settings, productLog)
Dan Willemsen01f0a052019-02-05 13:44:20 -0800247 }
248 return ret
249}
250
251func ParseProduct(p ProductBranch) ProductLog {
252 soongLog, err := ioutil.ReadFile(filepath.Join(p.Branch, p.Name, "soong.log"))
253 if err != nil {
254 log.Fatal(err)
255 }
256
257 ret := ProductLog{
258 ProductBranch: p,
259 Log: Log{
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800260 BuildBroken: map[string]*bool{},
261 HasBroken: map[string]int{},
Dan Willemsen01f0a052019-02-05 13:44:20 -0800262 },
263 }
264
265 lines := strings.Split(string(soongLog), "\n")
266 for _, line := range lines {
267 fields := strings.Split(line, " ")
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800268 if len(fields) < 5 {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800269 continue
270 }
271
272 if fields[3] == "TARGET_DEVICE" {
273 ret.Device = fields[4]
274 }
275
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800276 if fields[3] == "DEFAULT_WARNING_BUILD_MODULE_TYPES" {
277 ret.WarningModuleTypes = fields[4:]
278 }
279 if fields[3] == "DEFAULT_ERROR_BUILD_MODULE_TYPES" {
280 ret.ErrorModuleTypes = fields[4:]
281 }
282
Dan Willemsen01f0a052019-02-05 13:44:20 -0800283 if strings.HasPrefix(fields[3], "BUILD_BROKEN_") {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800284 ret.BuildBroken[fields[3]] = ParseBoolPtr(fields[4])
Dan Willemsen01f0a052019-02-05 13:44:20 -0800285 }
286 }
287
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800288 return ret
289}
290
291func ScanProduct(settings []Setting, l ProductLog) {
292 stdLog, err := ioutil.ReadFile(filepath.Join(l.Branch, l.Name, "std_full.log"))
Dan Willemsen01f0a052019-02-05 13:44:20 -0800293 if err != nil {
294 log.Fatal(err)
295 }
296 stdStr := string(stdLog)
297
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800298 for _, setting := range settings {
Dan Willemsen01f0a052019-02-05 13:44:20 -0800299 for _, warning := range setting.warnings {
300 if strings.Contains(stdStr, warning) {
Dan Willemsen9dfaa062020-01-29 10:09:16 -0800301 l.HasBroken[setting.name] += strings.Count(stdStr, warning)
Dan Willemsen01f0a052019-02-05 13:44:20 -0800302 }
303 }
304 }
Dan Willemsen01f0a052019-02-05 13:44:20 -0800305}
306
307func ParseBoolPtr(str string) *bool {
308 var ret *bool
309 if str != "" {
310 b := str == "true"
311 ret = &b
312 }
313 return ret
314}