blob: fcad1026c7f3958503e58c1798e8cadb010a74e3 [file] [log] [blame]
Dan Willemsenc2af0be2017-01-20 14:10:01 -08001// Copyright 2017 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
15package main
16
17import (
Lukacs T. Berkicef87b62021-08-10 15:01:13 +020018 "bufio"
Dan Willemsenc2af0be2017-01-20 14:10:01 -080019 "context"
20 "flag"
21 "fmt"
Dan Willemsen41538382018-08-31 19:51:35 -070022 "io"
Dan Willemsenf624fb92017-05-19 16:39:04 -070023 "io/ioutil"
Lukacs T. Berkicef87b62021-08-10 15:01:13 +020024 "log"
Dan Willemsenc2af0be2017-01-20 14:10:01 -080025 "os"
Lukacs T. Berkicef87b62021-08-10 15:01:13 +020026 "os/exec"
Dan Willemsenc2af0be2017-01-20 14:10:01 -080027 "path/filepath"
28 "runtime"
29 "strings"
30 "sync"
Dan Willemsen22de2162017-12-11 14:35:23 -080031 "syscall"
Steven Moreland552432e2017-03-29 19:26:09 -070032 "time"
Dan Willemsenc2af0be2017-01-20 14:10:01 -080033
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -070034 "android/soong/finder"
Dan Willemsenc2af0be2017-01-20 14:10:01 -080035 "android/soong/ui/build"
36 "android/soong/ui/logger"
Dan Willemsenb82471a2018-05-17 16:37:09 -070037 "android/soong/ui/status"
38 "android/soong/ui/terminal"
Dan Willemsend9f6fa22016-08-21 15:17:17 -070039 "android/soong/ui/tracer"
Dan Willemsene3480762017-11-07 11:23:27 -080040 "android/soong/zip"
Dan Willemsenc2af0be2017-01-20 14:10:01 -080041)
42
Dan Willemsen1bdbdec2019-12-27 09:54:11 -080043var numJobs = flag.Int("j", 0, "number of parallel jobs [0=autodetect]")
Dan Willemsenc2af0be2017-01-20 14:10:01 -080044
Dan Willemsene3480762017-11-07 11:23:27 -080045var keepArtifacts = flag.Bool("keep", false, "keep archives of artifacts")
Dan Willemsen41538382018-08-31 19:51:35 -070046var incremental = flag.Bool("incremental", false, "run in incremental mode (saving intermediates)")
Dan Willemsenc2af0be2017-01-20 14:10:01 -080047
48var outDir = flag.String("out", "", "path to store output directories (defaults to tmpdir under $OUT when empty)")
Dan Willemsenf624fb92017-05-19 16:39:04 -070049var alternateResultDir = flag.Bool("dist", false, "write select results to $DIST_DIR (or <out>/dist when empty)")
Dan Willemsenc2af0be2017-01-20 14:10:01 -080050
51var onlyConfig = flag.Bool("only-config", false, "Only run product config (not Soong or Kati)")
52var onlySoong = flag.Bool("only-soong", false, "Only run product config and Soong (not Kati)")
53
Dan Willemsen5ed900b2017-05-07 11:40:30 -070054var buildVariant = flag.String("variant", "eng", "build variant to use")
55
Dan Willemsen9609ad92019-12-05 15:22:41 -080056var shardCount = flag.Int("shard-count", 1, "split the products into multiple shards (to spread the build onto multiple machines, etc)")
57var shard = flag.Int("shard", 1, "1-indexed shard to execute")
58
Colin Crossf2f3d312020-12-17 11:29:31 -080059var skipProducts multipleStringArg
60var includeProducts multipleStringArg
61
62func init() {
63 flag.Var(&skipProducts, "skip-products", "comma-separated list of products to skip (known failures, etc)")
64 flag.Var(&includeProducts, "products", "comma-separated list of products to build")
65}
66
67// multipleStringArg is a flag.Value that takes comma separated lists and converts them to a
68// []string. The argument can be passed multiple times to append more values.
69type multipleStringArg []string
70
71func (m *multipleStringArg) String() string {
72 return strings.Join(*m, `, `)
73}
74
75func (m *multipleStringArg) Set(s string) error {
76 *m = append(*m, strings.Split(s, ",")...)
77 return nil
78}
79
Dan Willemsenf624fb92017-05-19 16:39:04 -070080const errorLeadingLines = 20
81const errorTrailingLines = 20
82
Dan Willemsenb82471a2018-05-17 16:37:09 -070083func errMsgFromLog(filename string) string {
84 if filename == "" {
85 return ""
Dan Willemsena4e43a72017-05-06 16:58:26 -070086 }
87
Dan Willemsenb82471a2018-05-17 16:37:09 -070088 data, err := ioutil.ReadFile(filename)
89 if err != nil {
90 return ""
Dan Willemsenf624fb92017-05-19 16:39:04 -070091 }
92
Dan Willemsenb82471a2018-05-17 16:37:09 -070093 lines := strings.Split(strings.TrimSpace(string(data)), "\n")
94 if len(lines) > errorLeadingLines+errorTrailingLines+1 {
95 lines[errorLeadingLines] = fmt.Sprintf("... skipping %d lines ...",
96 len(lines)-errorLeadingLines-errorTrailingLines)
Dan Willemsena4e43a72017-05-06 16:58:26 -070097
Dan Willemsenb82471a2018-05-17 16:37:09 -070098 lines = append(lines[:errorLeadingLines+1],
99 lines[len(lines)-errorTrailingLines:]...)
Dan Willemsena4e43a72017-05-06 16:58:26 -0700100 }
Dan Willemsenb82471a2018-05-17 16:37:09 -0700101 var buf strings.Builder
102 for _, line := range lines {
103 buf.WriteString("> ")
104 buf.WriteString(line)
105 buf.WriteString("\n")
Dan Willemsena4e43a72017-05-06 16:58:26 -0700106 }
Dan Willemsenb82471a2018-05-17 16:37:09 -0700107 return buf.String()
Dan Willemsena4e43a72017-05-06 16:58:26 -0700108}
109
Dan Willemsen22de2162017-12-11 14:35:23 -0800110// TODO(b/70370883): This tool uses a lot of open files -- over the default
111// soft limit of 1024 on some systems. So bump up to the hard limit until I fix
112// the algorithm.
113func setMaxFiles(log logger.Logger) {
114 var limits syscall.Rlimit
115
116 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
117 if err != nil {
118 log.Println("Failed to get file limit:", err)
119 return
120 }
121
122 log.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
123 if limits.Cur == limits.Max {
124 return
125 }
126
127 limits.Cur = limits.Max
128 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
129 if err != nil {
130 log.Println("Failed to increase file limit:", err)
131 }
132}
133
Jeff Gastonb61e3f72017-10-25 15:02:45 -0700134func inList(str string, list []string) bool {
135 for _, other := range list {
136 if str == other {
137 return true
138 }
139 }
140 return false
141}
142
Dan Willemsen41538382018-08-31 19:51:35 -0700143func copyFile(from, to string) error {
144 fromFile, err := os.Open(from)
145 if err != nil {
146 return err
147 }
148 defer fromFile.Close()
149
150 toFile, err := os.Create(to)
151 if err != nil {
152 return err
153 }
154 defer toFile.Close()
155
156 _, err = io.Copy(toFile, fromFile)
157 return err
158}
159
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700160type mpContext struct {
161 Context context.Context
162 Logger logger.Logger
163 Status status.ToolStatus
164 Tracer tracer.Tracer
165 Finder *finder.Finder
166 Config build.Config
167
168 LogsDir string
169}
170
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800171func main() {
Colin Cross097ed2a2019-06-08 21:48:58 -0700172 stdio := terminal.StdioImpl{}
Dan Willemsenb82471a2018-05-17 16:37:09 -0700173
Colin Crossc0b9f6b2019-09-23 12:44:54 -0700174 output := terminal.NewStatusOutput(stdio.Stdout(), "", false,
Colin Crosse0df1a32019-06-09 19:40:08 -0700175 build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
176
177 log := logger.New(output)
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800178 defer log.Cleanup()
179
180 flag.Parse()
181
182 ctx, cancel := context.WithCancel(context.Background())
183 defer cancel()
184
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700185 trace := tracer.New(log)
186 defer trace.Close()
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800187
Dan Willemsenb82471a2018-05-17 16:37:09 -0700188 stat := &status.Status{}
189 defer stat.Finish()
Colin Crosse0df1a32019-06-09 19:40:08 -0700190 stat.AddOutput(output)
Dan Willemsenb82471a2018-05-17 16:37:09 -0700191
Dan Willemsen34218ec2018-07-19 22:57:18 -0700192 var failures failureCount
193 stat.AddOutput(&failures)
194
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700195 build.SetupSignals(log, cancel, func() {
196 trace.Close()
197 log.Cleanup()
Dan Willemsenb82471a2018-05-17 16:37:09 -0700198 stat.Finish()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700199 })
200
Dan Willemsen59339a22018-07-22 21:18:45 -0700201 buildCtx := build.Context{ContextImpl: &build.ContextImpl{
Dan Willemsenb82471a2018-05-17 16:37:09 -0700202 Context: ctx,
203 Logger: log,
204 Tracer: trace,
Colin Crosse0df1a32019-06-09 19:40:08 -0700205 Writer: output,
Dan Willemsenb82471a2018-05-17 16:37:09 -0700206 Status: stat,
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700207 }}
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800208
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000209 args := ""
210 if *alternateResultDir {
211 args = "dist"
212 }
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200213
214 originalOutDir := os.Getenv("OUT_DIR")
215 if originalOutDir == "" {
216 originalOutDir = "out"
217 }
218
219 soongUi := "build/soong/soong_ui.bash"
220
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000221 config := build.NewConfig(buildCtx, args)
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800222 if *outDir == "" {
Dan Willemsen41538382018-08-31 19:51:35 -0700223 name := "multiproduct"
224 if !*incremental {
225 name += "-" + time.Now().Format("20060102150405")
226 }
Steven Moreland552432e2017-03-29 19:26:09 -0700227
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200228 *outDir = filepath.Join(originalOutDir, name)
Steven Moreland552432e2017-03-29 19:26:09 -0700229
Dan Willemsenf624fb92017-05-19 16:39:04 -0700230 // Ensure the empty files exist in the output directory
231 // containing our output directory too. This is mostly for
232 // safety, but also triggers the ninja_build file so that our
233 // build servers know that they can parse the output as if it
234 // was ninja output.
235 build.SetupOutDir(buildCtx, config)
236
Steven Moreland552432e2017-03-29 19:26:09 -0700237 if err := os.MkdirAll(*outDir, 0777); err != nil {
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800238 log.Fatalf("Failed to create tempdir: %v", err)
239 }
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800240 }
241 config.Environment().Set("OUT_DIR", *outDir)
242 log.Println("Output directory:", *outDir)
243
Dan Willemsene3480762017-11-07 11:23:27 -0800244 logsDir := filepath.Join(config.OutDir(), "logs")
245 os.MkdirAll(logsDir, 0777)
246
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800247 build.SetupOutDir(buildCtx, config)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000248
249 os.MkdirAll(config.LogsDir(), 0777)
250 log.SetOutput(filepath.Join(config.LogsDir(), "soong.log"))
251 trace.SetOutput(filepath.Join(config.LogsDir(), "build.trace"))
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800252
Dan Willemsen1bdbdec2019-12-27 09:54:11 -0800253 var jobs = *numJobs
254 if jobs < 1 {
255 jobs = runtime.NumCPU() / 4
256
257 ramGb := int(config.TotalRAM() / 1024 / 1024 / 1024)
Colin Crossf04fe9a2021-01-26 14:03:21 -0800258 if ramJobs := ramGb / 25; ramGb > 0 && jobs > ramJobs {
Dan Willemsen1bdbdec2019-12-27 09:54:11 -0800259 jobs = ramJobs
260 }
261
262 if jobs < 1 {
263 jobs = 1
264 }
265 }
266 log.Verbosef("Using %d parallel jobs", jobs)
267
Dan Willemsen22de2162017-12-11 14:35:23 -0800268 setMaxFiles(log)
269
Dan Willemsen04d76ef2018-05-15 00:52:29 -0700270 finder := build.NewSourceFinder(buildCtx, config)
271 defer finder.Shutdown()
272
273 build.FindSources(buildCtx, config, finder)
274
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700275 vars, err := build.DumpMakeVars(buildCtx, config, nil, []string{"all_named_products"})
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800276 if err != nil {
277 log.Fatal(err)
278 }
Jeff Gastonb61e3f72017-10-25 15:02:45 -0700279 var productsList []string
280 allProducts := strings.Fields(vars["all_named_products"])
281
Colin Crossf2f3d312020-12-17 11:29:31 -0800282 if len(includeProducts) > 0 {
283 var missingProducts []string
284 for _, product := range includeProducts {
Jeff Gastonb61e3f72017-10-25 15:02:45 -0700285 if inList(product, allProducts) {
286 productsList = append(productsList, product)
287 } else {
288 missingProducts = append(missingProducts, product)
289 }
290 }
291 if len(missingProducts) > 0 {
292 log.Fatalf("Products don't exist: %s\n", missingProducts)
293 }
294 } else {
295 productsList = allProducts
296 }
Dan Willemsen9957b9c2017-10-06 15:05:05 -0700297
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700298 finalProductsList := make([]string, 0, len(productsList))
Dan Willemsen9957b9c2017-10-06 15:05:05 -0700299 skipProduct := func(p string) bool {
Colin Crossf2f3d312020-12-17 11:29:31 -0800300 for _, s := range skipProducts {
Dan Willemsen9957b9c2017-10-06 15:05:05 -0700301 if p == s {
302 return true
303 }
304 }
305 return false
306 }
307 for _, product := range productsList {
308 if !skipProduct(product) {
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700309 finalProductsList = append(finalProductsList, product)
Dan Willemsen9957b9c2017-10-06 15:05:05 -0700310 } else {
311 log.Verbose("Skipping: ", product)
312 }
313 }
314
Dan Willemsen9609ad92019-12-05 15:22:41 -0800315 if *shard < 1 {
316 log.Fatalf("--shard value must be >= 1, not %d\n", *shard)
317 } else if *shardCount < 1 {
318 log.Fatalf("--shard-count value must be >= 1, not %d\n", *shardCount)
319 } else if *shard > *shardCount {
320 log.Fatalf("--shard (%d) must not be greater than --shard-count (%d)\n", *shard,
321 *shardCount)
322 } else if *shardCount > 1 {
323 finalProductsList = splitList(finalProductsList, *shardCount)[*shard-1]
324 }
325
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700326 log.Verbose("Got product list: ", finalProductsList)
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800327
Dan Willemsenb82471a2018-05-17 16:37:09 -0700328 s := buildCtx.Status.StartTool()
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700329 s.SetTotalActions(len(finalProductsList))
Dan Willemsena4e43a72017-05-06 16:58:26 -0700330
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700331 mpCtx := &mpContext{
332 Context: ctx,
333 Logger: log,
334 Status: s,
335 Tracer: trace,
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800336
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700337 Finder: finder,
338 Config: config,
Dan Willemsenf624fb92017-05-19 16:39:04 -0700339
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700340 LogsDir: logsDir,
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800341 }
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700342
343 products := make(chan string, len(productsList))
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800344 go func() {
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700345 defer close(products)
346 for _, product := range finalProductsList {
347 products <- product
348 }
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800349 }()
350
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700351 var wg sync.WaitGroup
Dan Willemsen1bdbdec2019-12-27 09:54:11 -0800352 for i := 0; i < jobs; i++ {
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700353 wg.Add(1)
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800354 go func() {
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700355 defer wg.Done()
356 for {
357 select {
358 case product := <-products:
359 if product == "" {
360 return
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800361 }
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200362 runSoongUiForProduct(mpCtx, product, soongUi)
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700363 }
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800364 }
365 }()
366 }
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700367 wg.Wait()
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800368
Dan Willemsene3480762017-11-07 11:23:27 -0800369 if *alternateResultDir {
370 args := zip.ZipArgs{
371 FileArgs: []zip.FileArg{
372 {GlobDir: logsDir, SourcePrefixToStrip: logsDir},
373 },
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000374 OutputFilePath: filepath.Join(config.RealDistDir(), "logs.zip"),
Dan Willemsene3480762017-11-07 11:23:27 -0800375 NumParallelJobs: runtime.NumCPU(),
376 CompressionLevel: 5,
377 }
Colin Cross05518bc2018-09-27 15:06:19 -0700378 if err := zip.Zip(args); err != nil {
Dan Willemsene3480762017-11-07 11:23:27 -0800379 log.Fatalf("Error zipping logs: %v", err)
380 }
381 }
382
Dan Willemsenb82471a2018-05-17 16:37:09 -0700383 s.Finish()
Dan Willemsen34218ec2018-07-19 22:57:18 -0700384
385 if failures == 1 {
386 log.Fatal("1 failure")
387 } else if failures > 1 {
388 log.Fatalf("%d failures", failures)
389 } else {
Colin Crosse0df1a32019-06-09 19:40:08 -0700390 fmt.Fprintln(output, "Success")
Dan Willemsen34218ec2018-07-19 22:57:18 -0700391 }
Dan Willemsenc2af0be2017-01-20 14:10:01 -0800392}
Dan Willemsen34218ec2018-07-19 22:57:18 -0700393
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200394func cleanupAfterProduct(outDir, productZip string) {
395 if *keepArtifacts {
396 args := zip.ZipArgs{
397 FileArgs: []zip.FileArg{
398 {
399 GlobDir: outDir,
400 SourcePrefixToStrip: outDir,
401 },
402 },
403 OutputFilePath: productZip,
404 NumParallelJobs: runtime.NumCPU(),
405 CompressionLevel: 5,
406 }
407 if err := zip.Zip(args); err != nil {
408 log.Fatalf("Error zipping artifacts: %v", err)
409 }
410 }
411 if !*incremental {
412 os.RemoveAll(outDir)
413 }
414}
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700415
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200416func runSoongUiForProduct(mpctx *mpContext, product, soongUi string) {
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700417 outDir := filepath.Join(mpctx.Config.OutDir(), product)
418 logsDir := filepath.Join(mpctx.LogsDir, product)
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200419 productZip := filepath.Join(mpctx.Config.OutDir(), product+".zip")
420 consoleLogPath := filepath.Join(logsDir, "std.log")
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700421
422 if err := os.MkdirAll(outDir, 0777); err != nil {
423 mpctx.Logger.Fatalf("Error creating out directory: %v", err)
424 }
425 if err := os.MkdirAll(logsDir, 0777); err != nil {
426 mpctx.Logger.Fatalf("Error creating log directory: %v", err)
427 }
428
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200429 consoleLogFile, err := os.Create(consoleLogPath)
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700430 if err != nil {
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200431 mpctx.Logger.Fatalf("Error creating console log file: %v", err)
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700432 }
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200433 defer consoleLogFile.Close()
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700434
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200435 consoleLogWriter := bufio.NewWriter(consoleLogFile)
436 defer consoleLogWriter.Flush()
437
438 args := []string{"--make-mode", "--skip-soong-tests", "--skip-ninja"}
439
440 if !*keepArtifacts {
441 args = append(args, "--empty-ninja-file")
442 }
443
444 if *onlyConfig {
445 args = append(args, "--config-only")
446 } else if *onlySoong {
447 args = append(args, "--soong-only")
448 }
449
450 if *alternateResultDir {
451 args = append(args, "dist")
452 }
453
454 cmd := exec.Command(soongUi, args...)
455 cmd.Stdout = consoleLogWriter
456 cmd.Stderr = consoleLogWriter
457 cmd.Env = append(os.Environ(),
458 "OUT_DIR="+outDir,
459 "TARGET_PRODUCT="+product,
460 "TARGET_BUILD_VARIANT="+*buildVariant,
461 "TARGET_BUILD_TYPE=release",
462 "TARGET_BUILD_APPS=",
463 "TARGET_BUILD_UNBUNDLED=")
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700464
465 action := &status.Action{
466 Description: product,
467 Outputs: []string{product},
468 }
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200469
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700470 mpctx.Status.StartAction(action)
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200471 defer cleanupAfterProduct(outDir, productZip)
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700472
473 before := time.Now()
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200474 err = cmd.Run()
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700475
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200476 if !*onlyConfig && !*onlySoong {
477 katiBuildNinjaFile := filepath.Join(outDir, "build-"+product+".ninja")
478 if after, err := os.Stat(katiBuildNinjaFile); err == nil && after.ModTime().After(before) {
479 err := copyFile(consoleLogPath, filepath.Join(filepath.Dir(consoleLogPath), "std_full.log"))
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700480 if err != nil {
481 log.Fatalf("Error copying log file: %s", err)
482 }
483 }
484 }
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700485 mpctx.Status.FinishAction(status.ActionResult{
486 Action: action,
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200487 Error: err,
Dan Willemsenbcc1dbf2018-09-04 18:09:47 -0700488 })
489}
490
Dan Willemsen34218ec2018-07-19 22:57:18 -0700491type failureCount int
492
493func (f *failureCount) StartAction(action *status.Action, counts status.Counts) {}
494
495func (f *failureCount) FinishAction(result status.ActionResult, counts status.Counts) {
496 if result.Error != nil {
497 *f += 1
498 }
499}
500
501func (f *failureCount) Message(level status.MsgLevel, message string) {
502 if level >= status.ErrorLvl {
503 *f += 1
504 }
505}
506
507func (f *failureCount) Flush() {}
Colin Crosse0df1a32019-06-09 19:40:08 -0700508
509func (f *failureCount) Write(p []byte) (int, error) {
510 // discard writes
511 return len(p), nil
512}
Dan Willemsen9609ad92019-12-05 15:22:41 -0800513
514func splitList(list []string, shardCount int) (ret [][]string) {
515 each := len(list) / shardCount
516 extra := len(list) % shardCount
517 for i := 0; i < shardCount; i++ {
518 count := each
519 if extra > 0 {
520 count += 1
521 extra -= 1
522 }
523 ret = append(ret, list[:count])
524 list = list[count:]
525 }
526 return
527}