• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 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 status
16
17import (
18	"compress/gzip"
19	"errors"
20	"fmt"
21	"io"
22	"io/ioutil"
23	"strings"
24
25	"github.com/golang/protobuf/proto"
26
27	"android/soong/ui/logger"
28	"android/soong/ui/status/build_error_proto"
29)
30
31type verboseLog struct {
32	w io.WriteCloser
33}
34
35func NewVerboseLog(log logger.Logger, filename string) StatusOutput {
36	if !strings.HasSuffix(filename, ".gz") {
37		filename += ".gz"
38	}
39
40	f, err := logger.CreateFileWithRotation(filename, 5)
41	if err != nil {
42		log.Println("Failed to create verbose log file:", err)
43		return nil
44	}
45
46	w := gzip.NewWriter(f)
47
48	return &verboseLog{
49		w: w,
50	}
51}
52
53func (v *verboseLog) StartAction(action *Action, counts Counts) {}
54
55func (v *verboseLog) FinishAction(result ActionResult, counts Counts) {
56	cmd := result.Command
57	if cmd == "" {
58		cmd = result.Description
59	}
60
61	fmt.Fprintf(v.w, "[%d/%d] %s\n", counts.FinishedActions, counts.TotalActions, cmd)
62
63	if result.Error != nil {
64		fmt.Fprintf(v.w, "FAILED: %s\n", strings.Join(result.Outputs, " "))
65	}
66
67	if result.Output != "" {
68		fmt.Fprintln(v.w, result.Output)
69	}
70}
71
72func (v *verboseLog) Flush() {
73	v.w.Close()
74}
75
76func (v *verboseLog) Message(level MsgLevel, message string) {
77	fmt.Fprintf(v.w, "%s%s\n", level.Prefix(), message)
78}
79
80func (v *verboseLog) Write(p []byte) (int, error) {
81	fmt.Fprint(v.w, string(p))
82	return len(p), nil
83}
84
85type errorLog struct {
86	w     io.WriteCloser
87	empty bool
88}
89
90func NewErrorLog(log logger.Logger, filename string) StatusOutput {
91	f, err := logger.CreateFileWithRotation(filename, 5)
92	if err != nil {
93		log.Println("Failed to create error log file:", err)
94		return nil
95	}
96
97	return &errorLog{
98		w:     f,
99		empty: true,
100	}
101}
102
103func (e *errorLog) StartAction(action *Action, counts Counts) {}
104
105func (e *errorLog) FinishAction(result ActionResult, counts Counts) {
106	if result.Error == nil {
107		return
108	}
109
110	if !e.empty {
111		fmt.Fprintf(e.w, "\n\n")
112	}
113	e.empty = false
114
115	fmt.Fprintf(e.w, "FAILED: %s\n", result.Description)
116
117	if len(result.Outputs) > 0 {
118		fmt.Fprintf(e.w, "Outputs: %s\n", strings.Join(result.Outputs, " "))
119	}
120
121	fmt.Fprintf(e.w, "Error: %s\n", result.Error)
122	if result.Command != "" {
123		fmt.Fprintf(e.w, "Command: %s\n", result.Command)
124	}
125	fmt.Fprintf(e.w, "Output:\n%s\n", result.Output)
126}
127
128func (e *errorLog) Flush() {
129	e.w.Close()
130}
131
132func (e *errorLog) Message(level MsgLevel, message string) {
133	if level < ErrorLvl {
134		return
135	}
136
137	if !e.empty {
138		fmt.Fprintf(e.w, "\n\n")
139	}
140	e.empty = false
141
142	fmt.Fprintf(e.w, "error: %s\n", message)
143}
144
145func (e *errorLog) Write(p []byte) (int, error) {
146	fmt.Fprint(e.w, string(p))
147	return len(p), nil
148}
149
150type errorProtoLog struct {
151	errorProto soong_build_error_proto.BuildError
152	filename   string
153	log        logger.Logger
154}
155
156func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
157	return &errorProtoLog{
158		errorProto: soong_build_error_proto.BuildError{},
159		filename:   filename,
160		log:        log,
161	}
162}
163
164func (e *errorProtoLog) StartAction(action *Action, counts Counts) {}
165
166func (e *errorProtoLog) FinishAction(result ActionResult, counts Counts) {
167	if result.Error == nil {
168		return
169	}
170
171	e.errorProto.ActionErrors = append(e.errorProto.ActionErrors, &soong_build_error_proto.BuildActionError{
172		Description: proto.String(result.Description),
173		Command:     proto.String(result.Command),
174		Output:      proto.String(result.Output),
175		Artifacts:   result.Outputs,
176		Error:       proto.String(result.Error.Error()),
177	})
178}
179
180func (e *errorProtoLog) Flush() {
181	data, err := proto.Marshal(&e.errorProto)
182	if err != nil {
183		e.log.Printf("Failed to marshal build status proto: %v\n", err)
184		return
185	}
186	err = ioutil.WriteFile(e.filename, []byte(data), 0644)
187	if err != nil {
188		e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
189	}
190}
191
192func (e *errorProtoLog) Message(level MsgLevel, message string) {
193	if level > ErrorLvl {
194		e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
195	}
196}
197
198func (e *errorProtoLog) Write(p []byte) (int, error) {
199	return 0, errors.New("not supported")
200}
201