xref: /aosp_15_r20/build/soong/ui/status/status.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Worker// Package status tracks actions run by various tools, combining the counts
16*333d2b36SAndroid Build Coastguard Worker// (total actions, currently running, started, finished), and giving that to
17*333d2b36SAndroid Build Coastguard Worker// multiple outputs.
18*333d2b36SAndroid Build Coastguard Workerpackage status
19*333d2b36SAndroid Build Coastguard Worker
20*333d2b36SAndroid Build Coastguard Workerimport (
21*333d2b36SAndroid Build Coastguard Worker	"sync"
22*333d2b36SAndroid Build Coastguard Worker	"time"
23*333d2b36SAndroid Build Coastguard Worker)
24*333d2b36SAndroid Build Coastguard Worker
25*333d2b36SAndroid Build Coastguard Worker// Action describes an action taken (or as Ninja calls them, Edges).
26*333d2b36SAndroid Build Coastguard Workertype Action struct {
27*333d2b36SAndroid Build Coastguard Worker	// Description is a shorter, more readable form of the command, meant
28*333d2b36SAndroid Build Coastguard Worker	// for users. It's optional, but one of either Description or Command
29*333d2b36SAndroid Build Coastguard Worker	// should be set.
30*333d2b36SAndroid Build Coastguard Worker	Description string
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard Worker	// Outputs is the (optional) list of outputs. Usually these are files,
33*333d2b36SAndroid Build Coastguard Worker	// but they can be any string.
34*333d2b36SAndroid Build Coastguard Worker	Outputs []string
35*333d2b36SAndroid Build Coastguard Worker
36*333d2b36SAndroid Build Coastguard Worker	// Inputs is the (optional) list of inputs. Usually these are files,
37*333d2b36SAndroid Build Coastguard Worker	// but they can be any string.
38*333d2b36SAndroid Build Coastguard Worker	Inputs []string
39*333d2b36SAndroid Build Coastguard Worker
40*333d2b36SAndroid Build Coastguard Worker	// Command is the actual command line executed to perform the action.
41*333d2b36SAndroid Build Coastguard Worker	// It's optional, but one of either Description or Command should be
42*333d2b36SAndroid Build Coastguard Worker	// set.
43*333d2b36SAndroid Build Coastguard Worker	Command string
44*333d2b36SAndroid Build Coastguard Worker
45*333d2b36SAndroid Build Coastguard Worker	// ChangedInputs is the (optional) list of inputs that have changed
46*333d2b36SAndroid Build Coastguard Worker	// since last time this action was run.
47*333d2b36SAndroid Build Coastguard Worker	ChangedInputs []string
48*333d2b36SAndroid Build Coastguard Worker}
49*333d2b36SAndroid Build Coastguard Worker
50*333d2b36SAndroid Build Coastguard Worker// ActionResult describes the result of running an Action.
51*333d2b36SAndroid Build Coastguard Workertype ActionResult struct {
52*333d2b36SAndroid Build Coastguard Worker	// Action is a pointer to the original Action struct.
53*333d2b36SAndroid Build Coastguard Worker	*Action
54*333d2b36SAndroid Build Coastguard Worker
55*333d2b36SAndroid Build Coastguard Worker	// Output is the output produced by the command (usually stdout&stderr
56*333d2b36SAndroid Build Coastguard Worker	// for Actions that run commands)
57*333d2b36SAndroid Build Coastguard Worker	Output string
58*333d2b36SAndroid Build Coastguard Worker
59*333d2b36SAndroid Build Coastguard Worker	// Error is nil if the Action succeeded, or set to an error if it
60*333d2b36SAndroid Build Coastguard Worker	// failed.
61*333d2b36SAndroid Build Coastguard Worker	Error error
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Worker	Stats ActionResultStats
64*333d2b36SAndroid Build Coastguard Worker}
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard Workertype ActionResultStats struct {
67*333d2b36SAndroid Build Coastguard Worker	// Number of milliseconds spent executing in user mode
68*333d2b36SAndroid Build Coastguard Worker	UserTime uint32
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Worker	// Number of milliseconds spent executing in kernel mode
71*333d2b36SAndroid Build Coastguard Worker	SystemTime uint32
72*333d2b36SAndroid Build Coastguard Worker
73*333d2b36SAndroid Build Coastguard Worker	// Max resident set size in kB
74*333d2b36SAndroid Build Coastguard Worker	MaxRssKB uint64
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	// Minor page faults
77*333d2b36SAndroid Build Coastguard Worker	MinorPageFaults uint64
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Worker	// Major page faults
80*333d2b36SAndroid Build Coastguard Worker	MajorPageFaults uint64
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	// IO input in kB
83*333d2b36SAndroid Build Coastguard Worker	IOInputKB uint64
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Worker	// IO output in kB
86*333d2b36SAndroid Build Coastguard Worker	IOOutputKB uint64
87*333d2b36SAndroid Build Coastguard Worker
88*333d2b36SAndroid Build Coastguard Worker	// Voluntary context switches
89*333d2b36SAndroid Build Coastguard Worker	VoluntaryContextSwitches uint64
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Worker	// Involuntary context switches
92*333d2b36SAndroid Build Coastguard Worker	InvoluntaryContextSwitches uint64
93*333d2b36SAndroid Build Coastguard Worker
94*333d2b36SAndroid Build Coastguard Worker	Tags string
95*333d2b36SAndroid Build Coastguard Worker}
96*333d2b36SAndroid Build Coastguard Worker
97*333d2b36SAndroid Build Coastguard Worker// Counts describes the number of actions in each state
98*333d2b36SAndroid Build Coastguard Workertype Counts struct {
99*333d2b36SAndroid Build Coastguard Worker	// TotalActions is the total number of expected changes.  This can
100*333d2b36SAndroid Build Coastguard Worker	// generally change up or down during a build, but it should never go
101*333d2b36SAndroid Build Coastguard Worker	// below the number of StartedActions
102*333d2b36SAndroid Build Coastguard Worker	TotalActions int
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard Worker	// RunningActions are the number of actions that are currently running
105*333d2b36SAndroid Build Coastguard Worker	// -- the number that have called StartAction, but not FinishAction.
106*333d2b36SAndroid Build Coastguard Worker	RunningActions int
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Worker	// StartedActions are the number of actions that have been started with
109*333d2b36SAndroid Build Coastguard Worker	// StartAction.
110*333d2b36SAndroid Build Coastguard Worker	StartedActions int
111*333d2b36SAndroid Build Coastguard Worker
112*333d2b36SAndroid Build Coastguard Worker	// FinishedActions are the number of actions that have been finished
113*333d2b36SAndroid Build Coastguard Worker	// with FinishAction.
114*333d2b36SAndroid Build Coastguard Worker	FinishedActions int
115*333d2b36SAndroid Build Coastguard Worker
116*333d2b36SAndroid Build Coastguard Worker	EstimatedTime time.Time
117*333d2b36SAndroid Build Coastguard Worker}
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Worker// ToolStatus is the interface used by tools to report on their Actions, and to
120*333d2b36SAndroid Build Coastguard Worker// present other information through a set of messaging functions.
121*333d2b36SAndroid Build Coastguard Workertype ToolStatus interface {
122*333d2b36SAndroid Build Coastguard Worker	// SetTotalActions sets the expected total number of actions that will
123*333d2b36SAndroid Build Coastguard Worker	// be started by this tool.
124*333d2b36SAndroid Build Coastguard Worker	//
125*333d2b36SAndroid Build Coastguard Worker	// This call be will ignored if it sets a number that is less than the
126*333d2b36SAndroid Build Coastguard Worker	// current number of started actions.
127*333d2b36SAndroid Build Coastguard Worker	SetTotalActions(total int)
128*333d2b36SAndroid Build Coastguard Worker	SetEstimatedTime(estimatedTime time.Time)
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Worker	// StartAction specifies that the associated action has been started by
131*333d2b36SAndroid Build Coastguard Worker	// the tool.
132*333d2b36SAndroid Build Coastguard Worker	//
133*333d2b36SAndroid Build Coastguard Worker	// A specific *Action should not be specified to StartAction more than
134*333d2b36SAndroid Build Coastguard Worker	// once, even if the previous action has already been finished, and the
135*333d2b36SAndroid Build Coastguard Worker	// contents rewritten.
136*333d2b36SAndroid Build Coastguard Worker	//
137*333d2b36SAndroid Build Coastguard Worker	// Do not re-use *Actions between different ToolStatus interfaces
138*333d2b36SAndroid Build Coastguard Worker	// either.
139*333d2b36SAndroid Build Coastguard Worker	StartAction(action *Action)
140*333d2b36SAndroid Build Coastguard Worker
141*333d2b36SAndroid Build Coastguard Worker	// FinishAction specifies the result of a particular Action.
142*333d2b36SAndroid Build Coastguard Worker	//
143*333d2b36SAndroid Build Coastguard Worker	// The *Action embedded in the ActionResult structure must have already
144*333d2b36SAndroid Build Coastguard Worker	// been passed to StartAction (on this interface).
145*333d2b36SAndroid Build Coastguard Worker	//
146*333d2b36SAndroid Build Coastguard Worker	// Do not call FinishAction twice for the same *Action.
147*333d2b36SAndroid Build Coastguard Worker	FinishAction(result ActionResult)
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker	// Verbose takes a non-important message that is never printed to the
150*333d2b36SAndroid Build Coastguard Worker	// screen, but is in the verbose build log, etc
151*333d2b36SAndroid Build Coastguard Worker	Verbose(msg string)
152*333d2b36SAndroid Build Coastguard Worker	// Status takes a less important message that may be printed to the
153*333d2b36SAndroid Build Coastguard Worker	// screen, but overwritten by another status message. The full message
154*333d2b36SAndroid Build Coastguard Worker	// will still appear in the verbose build log.
155*333d2b36SAndroid Build Coastguard Worker	Status(msg string)
156*333d2b36SAndroid Build Coastguard Worker	// Print takes an message and displays it to the screen and other
157*333d2b36SAndroid Build Coastguard Worker	// output logs, etc.
158*333d2b36SAndroid Build Coastguard Worker	Print(msg string)
159*333d2b36SAndroid Build Coastguard Worker	// Error is similar to Print, but treats it similarly to a failed
160*333d2b36SAndroid Build Coastguard Worker	// action, showing it in the error logs, etc.
161*333d2b36SAndroid Build Coastguard Worker	Error(msg string)
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Worker	// Finish marks the end of all Actions being run by this tool.
164*333d2b36SAndroid Build Coastguard Worker	//
165*333d2b36SAndroid Build Coastguard Worker	// SetTotalEdges, StartAction, and FinishAction should not be called
166*333d2b36SAndroid Build Coastguard Worker	// after Finish.
167*333d2b36SAndroid Build Coastguard Worker	Finish()
168*333d2b36SAndroid Build Coastguard Worker}
169*333d2b36SAndroid Build Coastguard Worker
170*333d2b36SAndroid Build Coastguard Worker// MsgLevel specifies the importance of a particular log message. See the
171*333d2b36SAndroid Build Coastguard Worker// descriptions in ToolStatus: Verbose, Status, Print, Error.
172*333d2b36SAndroid Build Coastguard Workertype MsgLevel int
173*333d2b36SAndroid Build Coastguard Worker
174*333d2b36SAndroid Build Coastguard Workerconst (
175*333d2b36SAndroid Build Coastguard Worker	VerboseLvl MsgLevel = iota
176*333d2b36SAndroid Build Coastguard Worker	StatusLvl
177*333d2b36SAndroid Build Coastguard Worker	PrintLvl
178*333d2b36SAndroid Build Coastguard Worker	ErrorLvl
179*333d2b36SAndroid Build Coastguard Worker)
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Workerfunc (l MsgLevel) Prefix() string {
182*333d2b36SAndroid Build Coastguard Worker	switch l {
183*333d2b36SAndroid Build Coastguard Worker	case VerboseLvl:
184*333d2b36SAndroid Build Coastguard Worker		return "verbose: "
185*333d2b36SAndroid Build Coastguard Worker	case StatusLvl:
186*333d2b36SAndroid Build Coastguard Worker		return "status: "
187*333d2b36SAndroid Build Coastguard Worker	case PrintLvl:
188*333d2b36SAndroid Build Coastguard Worker		return ""
189*333d2b36SAndroid Build Coastguard Worker	case ErrorLvl:
190*333d2b36SAndroid Build Coastguard Worker		return "error: "
191*333d2b36SAndroid Build Coastguard Worker	default:
192*333d2b36SAndroid Build Coastguard Worker		panic("Unknown message level")
193*333d2b36SAndroid Build Coastguard Worker	}
194*333d2b36SAndroid Build Coastguard Worker}
195*333d2b36SAndroid Build Coastguard Worker
196*333d2b36SAndroid Build Coastguard Worker// StatusOutput is the interface used to get status information as a Status
197*333d2b36SAndroid Build Coastguard Worker// output.
198*333d2b36SAndroid Build Coastguard Worker//
199*333d2b36SAndroid Build Coastguard Worker// All of the functions here are guaranteed to be called by Status while
200*333d2b36SAndroid Build Coastguard Worker// holding it's internal lock, so it's safe to assume a single caller at any
201*333d2b36SAndroid Build Coastguard Worker// time, and that the ordering of calls will be correct. It is not safe to call
202*333d2b36SAndroid Build Coastguard Worker// back into the Status, or one of its ToolStatus interfaces.
203*333d2b36SAndroid Build Coastguard Workertype StatusOutput interface {
204*333d2b36SAndroid Build Coastguard Worker	// StartAction will be called once every time ToolStatus.StartAction is
205*333d2b36SAndroid Build Coastguard Worker	// called. counts will include the current counters across all
206*333d2b36SAndroid Build Coastguard Worker	// ToolStatus instances, including ones that have been finished.
207*333d2b36SAndroid Build Coastguard Worker	StartAction(action *Action, counts Counts)
208*333d2b36SAndroid Build Coastguard Worker
209*333d2b36SAndroid Build Coastguard Worker	// FinishAction will be called once every time ToolStatus.FinishAction
210*333d2b36SAndroid Build Coastguard Worker	// is called. counts will include the current counters across all
211*333d2b36SAndroid Build Coastguard Worker	// ToolStatus instances, including ones that have been finished.
212*333d2b36SAndroid Build Coastguard Worker	FinishAction(result ActionResult, counts Counts)
213*333d2b36SAndroid Build Coastguard Worker
214*333d2b36SAndroid Build Coastguard Worker	// Message is the equivalent of ToolStatus.Verbose/Status/Print/Error,
215*333d2b36SAndroid Build Coastguard Worker	// but the level is specified as an argument.
216*333d2b36SAndroid Build Coastguard Worker	Message(level MsgLevel, msg string)
217*333d2b36SAndroid Build Coastguard Worker
218*333d2b36SAndroid Build Coastguard Worker	// Flush is called when your outputs should be flushed / closed. No
219*333d2b36SAndroid Build Coastguard Worker	// output is expected after this call.
220*333d2b36SAndroid Build Coastguard Worker	Flush()
221*333d2b36SAndroid Build Coastguard Worker
222*333d2b36SAndroid Build Coastguard Worker	// Write lets StatusOutput implement io.Writer
223*333d2b36SAndroid Build Coastguard Worker	Write(p []byte) (n int, err error)
224*333d2b36SAndroid Build Coastguard Worker}
225*333d2b36SAndroid Build Coastguard Worker
226*333d2b36SAndroid Build Coastguard Worker// Status is the multiplexer / accumulator between ToolStatus instances (via
227*333d2b36SAndroid Build Coastguard Worker// StartTool) and StatusOutputs (via AddOutput). There's generally one of these
228*333d2b36SAndroid Build Coastguard Worker// per build process (though tools like multiproduct_kati may have multiple
229*333d2b36SAndroid Build Coastguard Worker// independent versions).
230*333d2b36SAndroid Build Coastguard Workertype Status struct {
231*333d2b36SAndroid Build Coastguard Worker	counts  Counts
232*333d2b36SAndroid Build Coastguard Worker	outputs []StatusOutput
233*333d2b36SAndroid Build Coastguard Worker
234*333d2b36SAndroid Build Coastguard Worker	// Protects counts and outputs, and allows each output to
235*333d2b36SAndroid Build Coastguard Worker	// expect only a single caller at a time.
236*333d2b36SAndroid Build Coastguard Worker	lock sync.Mutex
237*333d2b36SAndroid Build Coastguard Worker}
238*333d2b36SAndroid Build Coastguard Worker
239*333d2b36SAndroid Build Coastguard Worker// AddOutput attaches an output to this object. It's generally expected that an
240*333d2b36SAndroid Build Coastguard Worker// output is attached to a single Status instance.
241*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) AddOutput(output StatusOutput) {
242*333d2b36SAndroid Build Coastguard Worker	if output == nil {
243*333d2b36SAndroid Build Coastguard Worker		return
244*333d2b36SAndroid Build Coastguard Worker	}
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
247*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
248*333d2b36SAndroid Build Coastguard Worker
249*333d2b36SAndroid Build Coastguard Worker	s.outputs = append(s.outputs, output)
250*333d2b36SAndroid Build Coastguard Worker}
251*333d2b36SAndroid Build Coastguard Worker
252*333d2b36SAndroid Build Coastguard Worker// StartTool returns a new ToolStatus instance to report the status of a tool.
253*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) StartTool() ToolStatus {
254*333d2b36SAndroid Build Coastguard Worker	return &toolStatus{
255*333d2b36SAndroid Build Coastguard Worker		status: s,
256*333d2b36SAndroid Build Coastguard Worker	}
257*333d2b36SAndroid Build Coastguard Worker}
258*333d2b36SAndroid Build Coastguard Worker
259*333d2b36SAndroid Build Coastguard Worker// Finish will call Flush on all the outputs, generally flushing or closing all
260*333d2b36SAndroid Build Coastguard Worker// of their outputs. Do not call any other functions on this instance or any
261*333d2b36SAndroid Build Coastguard Worker// associated ToolStatus instances after this has been called.
262*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) Finish() {
263*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
264*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
265*333d2b36SAndroid Build Coastguard Worker
266*333d2b36SAndroid Build Coastguard Worker	for _, o := range s.outputs {
267*333d2b36SAndroid Build Coastguard Worker		o.Flush()
268*333d2b36SAndroid Build Coastguard Worker	}
269*333d2b36SAndroid Build Coastguard Worker}
270*333d2b36SAndroid Build Coastguard Worker
271*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) updateTotalActions(diff int) {
272*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
273*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
274*333d2b36SAndroid Build Coastguard Worker
275*333d2b36SAndroid Build Coastguard Worker	s.counts.TotalActions += diff
276*333d2b36SAndroid Build Coastguard Worker}
277*333d2b36SAndroid Build Coastguard Worker
278*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) SetEstimatedTime(estimatedTime time.Time) {
279*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
280*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
281*333d2b36SAndroid Build Coastguard Worker
282*333d2b36SAndroid Build Coastguard Worker	s.counts.EstimatedTime = estimatedTime
283*333d2b36SAndroid Build Coastguard Worker}
284*333d2b36SAndroid Build Coastguard Worker
285*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) startAction(action *Action) {
286*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
287*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
288*333d2b36SAndroid Build Coastguard Worker
289*333d2b36SAndroid Build Coastguard Worker	s.counts.RunningActions += 1
290*333d2b36SAndroid Build Coastguard Worker	s.counts.StartedActions += 1
291*333d2b36SAndroid Build Coastguard Worker
292*333d2b36SAndroid Build Coastguard Worker	for _, o := range s.outputs {
293*333d2b36SAndroid Build Coastguard Worker		o.StartAction(action, s.counts)
294*333d2b36SAndroid Build Coastguard Worker	}
295*333d2b36SAndroid Build Coastguard Worker}
296*333d2b36SAndroid Build Coastguard Worker
297*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) finishAction(result ActionResult) {
298*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
299*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
300*333d2b36SAndroid Build Coastguard Worker
301*333d2b36SAndroid Build Coastguard Worker	s.counts.RunningActions -= 1
302*333d2b36SAndroid Build Coastguard Worker	s.counts.FinishedActions += 1
303*333d2b36SAndroid Build Coastguard Worker
304*333d2b36SAndroid Build Coastguard Worker	for _, o := range s.outputs {
305*333d2b36SAndroid Build Coastguard Worker		o.FinishAction(result, s.counts)
306*333d2b36SAndroid Build Coastguard Worker	}
307*333d2b36SAndroid Build Coastguard Worker}
308*333d2b36SAndroid Build Coastguard Worker
309*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) message(level MsgLevel, msg string) {
310*333d2b36SAndroid Build Coastguard Worker	s.lock.Lock()
311*333d2b36SAndroid Build Coastguard Worker	defer s.lock.Unlock()
312*333d2b36SAndroid Build Coastguard Worker
313*333d2b36SAndroid Build Coastguard Worker	for _, o := range s.outputs {
314*333d2b36SAndroid Build Coastguard Worker		o.Message(level, msg)
315*333d2b36SAndroid Build Coastguard Worker	}
316*333d2b36SAndroid Build Coastguard Worker}
317*333d2b36SAndroid Build Coastguard Worker
318*333d2b36SAndroid Build Coastguard Workerfunc (s *Status) Status(msg string) {
319*333d2b36SAndroid Build Coastguard Worker	s.message(StatusLvl, msg)
320*333d2b36SAndroid Build Coastguard Worker}
321*333d2b36SAndroid Build Coastguard Worker
322*333d2b36SAndroid Build Coastguard Workertype toolStatus struct {
323*333d2b36SAndroid Build Coastguard Worker	status *Status
324*333d2b36SAndroid Build Coastguard Worker
325*333d2b36SAndroid Build Coastguard Worker	counts Counts
326*333d2b36SAndroid Build Coastguard Worker	// Protects counts
327*333d2b36SAndroid Build Coastguard Worker	lock sync.Mutex
328*333d2b36SAndroid Build Coastguard Worker}
329*333d2b36SAndroid Build Coastguard Worker
330*333d2b36SAndroid Build Coastguard Workervar _ ToolStatus = (*toolStatus)(nil)
331*333d2b36SAndroid Build Coastguard Worker
332*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) SetTotalActions(total int) {
333*333d2b36SAndroid Build Coastguard Worker	diff := 0
334*333d2b36SAndroid Build Coastguard Worker
335*333d2b36SAndroid Build Coastguard Worker	d.lock.Lock()
336*333d2b36SAndroid Build Coastguard Worker	if total >= d.counts.StartedActions && total != d.counts.TotalActions {
337*333d2b36SAndroid Build Coastguard Worker		diff = total - d.counts.TotalActions
338*333d2b36SAndroid Build Coastguard Worker		d.counts.TotalActions = total
339*333d2b36SAndroid Build Coastguard Worker	}
340*333d2b36SAndroid Build Coastguard Worker	d.lock.Unlock()
341*333d2b36SAndroid Build Coastguard Worker
342*333d2b36SAndroid Build Coastguard Worker	if diff != 0 {
343*333d2b36SAndroid Build Coastguard Worker		d.status.updateTotalActions(diff)
344*333d2b36SAndroid Build Coastguard Worker	}
345*333d2b36SAndroid Build Coastguard Worker}
346*333d2b36SAndroid Build Coastguard Worker
347*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) SetEstimatedTime(estimatedTime time.Time) {
348*333d2b36SAndroid Build Coastguard Worker	d.status.SetEstimatedTime(estimatedTime)
349*333d2b36SAndroid Build Coastguard Worker}
350*333d2b36SAndroid Build Coastguard Worker
351*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) StartAction(action *Action) {
352*333d2b36SAndroid Build Coastguard Worker	totalDiff := 0
353*333d2b36SAndroid Build Coastguard Worker
354*333d2b36SAndroid Build Coastguard Worker	d.lock.Lock()
355*333d2b36SAndroid Build Coastguard Worker	d.counts.RunningActions += 1
356*333d2b36SAndroid Build Coastguard Worker	d.counts.StartedActions += 1
357*333d2b36SAndroid Build Coastguard Worker
358*333d2b36SAndroid Build Coastguard Worker	if d.counts.StartedActions > d.counts.TotalActions {
359*333d2b36SAndroid Build Coastguard Worker		totalDiff = d.counts.StartedActions - d.counts.TotalActions
360*333d2b36SAndroid Build Coastguard Worker		d.counts.TotalActions = d.counts.StartedActions
361*333d2b36SAndroid Build Coastguard Worker	}
362*333d2b36SAndroid Build Coastguard Worker	d.lock.Unlock()
363*333d2b36SAndroid Build Coastguard Worker
364*333d2b36SAndroid Build Coastguard Worker	if totalDiff != 0 {
365*333d2b36SAndroid Build Coastguard Worker		d.status.updateTotalActions(totalDiff)
366*333d2b36SAndroid Build Coastguard Worker	}
367*333d2b36SAndroid Build Coastguard Worker	d.status.startAction(action)
368*333d2b36SAndroid Build Coastguard Worker}
369*333d2b36SAndroid Build Coastguard Worker
370*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) FinishAction(result ActionResult) {
371*333d2b36SAndroid Build Coastguard Worker	d.lock.Lock()
372*333d2b36SAndroid Build Coastguard Worker	d.counts.RunningActions -= 1
373*333d2b36SAndroid Build Coastguard Worker	d.counts.FinishedActions += 1
374*333d2b36SAndroid Build Coastguard Worker	d.lock.Unlock()
375*333d2b36SAndroid Build Coastguard Worker
376*333d2b36SAndroid Build Coastguard Worker	d.status.finishAction(result)
377*333d2b36SAndroid Build Coastguard Worker}
378*333d2b36SAndroid Build Coastguard Worker
379*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) Verbose(msg string) {
380*333d2b36SAndroid Build Coastguard Worker	d.status.message(VerboseLvl, msg)
381*333d2b36SAndroid Build Coastguard Worker}
382*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) Status(msg string) {
383*333d2b36SAndroid Build Coastguard Worker	d.status.message(StatusLvl, msg)
384*333d2b36SAndroid Build Coastguard Worker}
385*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) Print(msg string) {
386*333d2b36SAndroid Build Coastguard Worker	d.status.message(PrintLvl, msg)
387*333d2b36SAndroid Build Coastguard Worker}
388*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) Error(msg string) {
389*333d2b36SAndroid Build Coastguard Worker	d.status.message(ErrorLvl, msg)
390*333d2b36SAndroid Build Coastguard Worker}
391*333d2b36SAndroid Build Coastguard Worker
392*333d2b36SAndroid Build Coastguard Workerfunc (d *toolStatus) Finish() {
393*333d2b36SAndroid Build Coastguard Worker	d.lock.Lock()
394*333d2b36SAndroid Build Coastguard Worker	defer d.lock.Unlock()
395*333d2b36SAndroid Build Coastguard Worker
396*333d2b36SAndroid Build Coastguard Worker	if d.counts.TotalActions != d.counts.StartedActions {
397*333d2b36SAndroid Build Coastguard Worker		d.status.updateTotalActions(d.counts.StartedActions - d.counts.TotalActions)
398*333d2b36SAndroid Build Coastguard Worker	}
399*333d2b36SAndroid Build Coastguard Worker
400*333d2b36SAndroid Build Coastguard Worker	// TODO: update status to correct running/finished edges?
401*333d2b36SAndroid Build Coastguard Worker	d.counts.RunningActions = 0
402*333d2b36SAndroid Build Coastguard Worker	d.counts.TotalActions = d.counts.StartedActions
403*333d2b36SAndroid Build Coastguard Worker}
404