pw_build: Fix inaccurate 'num started' display in wrap-ninja

This commit fixes an issue where pw-wrap-ninja, when logging actions
with --log-actions, would incorrectly display 'batched' "number of
events started". That is, ten actions would be printed, all of which
would have the same "number started", then it would jump up and more
events would be printed.

This happened because the UI, which updates every 100ms, would always
query the most recent number of events started/finished and print that.

This commit addresses the issue by saving the current value of
started/finished/total with each event when they occur, so that the UI
can accurately print those values.

Change-Id: I7c4fe00122e2fa529e64312c41ec2dea7e0b7c18
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/126986
Reviewed-by: Rob Mohr <mohrr@google.com>
Pigweed-Auto-Submit: Eli Lipsitz <elipsitz@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_build/py/pw_build/wrap_ninja.py b/pw_build/py/pw_build/wrap_ninja.py
index 01e6d94..bbbc727 100644
--- a/pw_build/py/pw_build/wrap_ninja.py
+++ b/pw_build/py/pw_build/wrap_ninja.py
@@ -190,11 +190,17 @@
         action: The action this event relates to, if any.
         message: The log message associated with this event, if it an
             'ACTION_LOG' event.
+        num_started: The number of started actions when this event occurred.
+        num_finished: The number of finished actions when this event occurred.
+        num_total: The total number of actions when this event occurred.
     """
 
     kind: NinjaEventKind
     action: Optional[NinjaAction] = None
     log_message: Optional[str] = None
+    num_started: int = 0
+    num_finished: int = 0
+    num_total: int = 0
 
 
 class Ninja:
@@ -329,7 +335,7 @@
                 if actions_started == 1 and actions_finished == 0:
                     for action in self.running_actions.values():
                         action.end_time = time.time()
-                        self.events.append(
+                        self._add_event(
                             NinjaEvent(NinjaEventKind.ACTION_FINISHED, action)
                         )
                     self.running_actions = {}
@@ -341,7 +347,7 @@
                     )
                     if action.jobs == 0:
                         self.actions.append(action)
-                        self.events.append(
+                        self._add_event(
                             NinjaEvent(NinjaEventKind.ACTION_STARTED, action)
                         )
                     action.jobs += 1
@@ -353,14 +359,14 @@
                         self.running_actions.pop(name)
                         self.last_action_completed = action
                         action.end_time = time.time()
-                        self.events.append(
+                        self._add_event(
                             NinjaEvent(NinjaEventKind.ACTION_FINISHED, action)
                         )
             else:
                 context_action = None
                 if not line.startswith('ninja: '):
                     context_action = self.last_action_completed
-                self.events.append(
+                self._add_event(
                     NinjaEvent(
                         NinjaEventKind.ACTION_LOG,
                         action=context_action,
@@ -368,6 +374,13 @@
                     )
                 )
 
+    def _add_event(self, event: NinjaEvent) -> None:
+        """Add a new event to the event queue."""
+        event.num_started = self.num_started
+        event.num_finished = self.num_finished
+        event.num_total = self.num_total
+        self.events.append(event)
+
     def write_trace(self, file: IO[str]) -> None:
         """Write a Chromium trace_event-formatted trace to a file."""
         now = time.time()
@@ -449,7 +462,7 @@
         if event.kind == NinjaEventKind.ACTION_STARTED and show_started:
             assert event.action
             self._renderer.print_line(
-                f'[{self._ninja.num_finished}/{self._ninja.num_total}] '
+                f'[{event.num_finished}/{event.num_total}] '
                 f'Started  [{event.action.name}]'
             )
 
@@ -459,7 +472,7 @@
                 event.action.end_time - event.action.start_time
             )
             self._renderer.print_line(
-                f'[{self._ninja.num_finished}/{self._ninja.num_total}] '
+                f'[{event.num_finished}/{event.num_total}] '
                 f'Finished [{event.action.name}] ({duration})'
             )