123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- // Copyright 2018 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package status
- import (
- "compress/gzip"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strings"
- "google.golang.org/protobuf/proto"
- "android/soong/ui/logger"
- soong_build_error_proto "android/soong/ui/status/build_error_proto"
- soong_build_progress_proto "android/soong/ui/status/build_progress_proto"
- )
- type verboseLog struct {
- w io.WriteCloser
- }
- func NewVerboseLog(log logger.Logger, filename string) StatusOutput {
- if !strings.HasSuffix(filename, ".gz") {
- filename += ".gz"
- }
- f, err := logger.CreateFileWithRotation(filename, 5)
- if err != nil {
- log.Println("Failed to create verbose log file:", err)
- return nil
- }
- w := gzip.NewWriter(f)
- return &verboseLog{
- w: w,
- }
- }
- func (v *verboseLog) StartAction(action *Action, counts Counts) {}
- func (v *verboseLog) FinishAction(result ActionResult, counts Counts) {
- cmd := result.Command
- if cmd == "" {
- cmd = result.Description
- }
- fmt.Fprintf(v.w, "[%d/%d] %s\n", counts.FinishedActions, counts.TotalActions, cmd)
- if result.Error != nil {
- fmt.Fprintf(v.w, "FAILED: %s\n", strings.Join(result.Outputs, " "))
- }
- if result.Output != "" {
- fmt.Fprintln(v.w, result.Output)
- }
- }
- func (v *verboseLog) Flush() {
- v.w.Close()
- }
- func (v *verboseLog) Message(level MsgLevel, message string) {
- fmt.Fprintf(v.w, "%s%s\n", level.Prefix(), message)
- }
- func (v *verboseLog) Write(p []byte) (int, error) {
- fmt.Fprint(v.w, string(p))
- return len(p), nil
- }
- type errorLog struct {
- w io.WriteCloser
- empty bool
- }
- func NewErrorLog(log logger.Logger, filename string) StatusOutput {
- f, err := logger.CreateFileWithRotation(filename, 5)
- if err != nil {
- log.Println("Failed to create error log file:", err)
- return nil
- }
- return &errorLog{
- w: f,
- empty: true,
- }
- }
- func (e *errorLog) StartAction(action *Action, counts Counts) {}
- func (e *errorLog) FinishAction(result ActionResult, counts Counts) {
- if result.Error == nil {
- return
- }
- if !e.empty {
- fmt.Fprintf(e.w, "\n\n")
- }
- e.empty = false
- fmt.Fprintf(e.w, "FAILED: %s\n", result.Description)
- if len(result.Outputs) > 0 {
- fmt.Fprintf(e.w, "Outputs: %s\n", strings.Join(result.Outputs, " "))
- }
- fmt.Fprintf(e.w, "Error: %s\n", result.Error)
- if result.Command != "" {
- fmt.Fprintf(e.w, "Command: %s\n", result.Command)
- }
- fmt.Fprintf(e.w, "Output:\n%s\n", result.Output)
- }
- func (e *errorLog) Flush() {
- e.w.Close()
- }
- func (e *errorLog) Message(level MsgLevel, message string) {
- if level < ErrorLvl {
- return
- }
- if !e.empty {
- fmt.Fprintf(e.w, "\n\n")
- }
- e.empty = false
- fmt.Fprintf(e.w, "error: %s\n", message)
- }
- func (e *errorLog) Write(p []byte) (int, error) {
- fmt.Fprint(e.w, string(p))
- return len(p), nil
- }
- type errorProtoLog struct {
- errorProto soong_build_error_proto.BuildError
- filename string
- log logger.Logger
- }
- func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
- os.Remove(filename)
- return &errorProtoLog{
- errorProto: soong_build_error_proto.BuildError{},
- filename: filename,
- log: log,
- }
- }
- func (e *errorProtoLog) StartAction(action *Action, counts Counts) {}
- func (e *errorProtoLog) FinishAction(result ActionResult, counts Counts) {
- if result.Error == nil {
- return
- }
- e.errorProto.ActionErrors = append(e.errorProto.ActionErrors, &soong_build_error_proto.BuildActionError{
- Description: proto.String(result.Description),
- Command: proto.String(result.Command),
- Output: proto.String(result.Output),
- Artifacts: result.Outputs,
- Error: proto.String(result.Error.Error()),
- })
- err := writeToFile(&e.errorProto, e.filename)
- if err != nil {
- e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
- }
- }
- func (e *errorProtoLog) Flush() {
- //Not required.
- }
- func (e *errorProtoLog) Message(level MsgLevel, message string) {
- if level > ErrorLvl {
- e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
- }
- }
- func (e *errorProtoLog) Write(p []byte) (int, error) {
- return 0, errors.New("not supported")
- }
- type buildProgressLog struct {
- filename string
- log logger.Logger
- failedActions uint64
- }
- func NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
- return &buildProgressLog{
- filename: filename,
- log: log,
- failedActions: 0,
- }
- }
- func (b *buildProgressLog) StartAction(action *Action, counts Counts) {
- b.updateCounters(counts)
- }
- func (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
- if result.Error != nil {
- b.failedActions++
- }
- b.updateCounters(counts)
- }
- func (b *buildProgressLog) Flush() {
- //Not required.
- }
- func (b *buildProgressLog) Message(level MsgLevel, message string) {
- // Not required.
- }
- func (b *buildProgressLog) Write(p []byte) (int, error) {
- return 0, errors.New("not supported")
- }
- func (b *buildProgressLog) updateCounters(counts Counts) {
- err := writeToFile(
- &soong_build_progress_proto.BuildProgress{
- CurrentActions: proto.Uint64(uint64(counts.RunningActions)),
- FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
- TotalActions: proto.Uint64(uint64(counts.TotalActions)),
- FailedActions: proto.Uint64(b.failedActions),
- },
- b.filename,
- )
- if err != nil {
- b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
- }
- }
- func writeToFile(pb proto.Message, outputPath string) (err error) {
- data, err := proto.Marshal(pb)
- if err != nil {
- return err
- }
- tempPath := outputPath + ".tmp"
- err = ioutil.WriteFile(tempPath, []byte(data), 0644)
- if err != nil {
- return err
- }
- err = os.Rename(tempPath, outputPath)
- if err != nil {
- return err
- }
- return nil
- }
|