Miscellaneous fixes to post_build_ninja_summary.py

In Python 3 dict.values() is not a sortable type so it must be converted
to a list prior to returning targets data from the ReadTargets function.

In Python 3 you cannot compare arbitrary objects. This could happen when
sorting task_start_stop_times if the time and types were identical. This
is fixed by using the first two entries in the tuple as the sorting key.

When a .ninja_log file is corrupt it triggers a diagnostic message which
has only caused confusion. This changes that message to suggest the most
likely root cause (corruption) since that is the only cause I have seen.

If a build step generates multiple targets with long names then wrapping
of lines may occur. To avoid that the target description size is capped.

Bug: 941669
Change-Id: I2a808d2629a639e231ce2dbf2dab41251110b156
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2432409
Auto-Submit: Bruce Dawson <brucedawson@chromium.org>
Commit-Queue: Dirk Pranke <dpranke@google.com>
Reviewed-by: Dirk Pranke <dpranke@google.com>
diff --git a/post_build_ninja_summary.py b/post_build_ninja_summary.py
index 25c4797..99cbc85 100644
--- a/post_build_ninja_summary.py
+++ b/post_build_ninja_summary.py
@@ -104,17 +104,14 @@
 
     def DescribeTargets(self):
         """Returns a printable string that summarizes the targets."""
-        if len(self.targets) == 1:
-          return self.targets[0]
         # Some build steps generate dozens of outputs - handle them sanely.
-        # It's a bit odd that if there are three targets we return all three
-        # but if there are more than three we just return two, but this works
-        # well in practice.
-        elif len(self.targets) > 3:
-          return '(%d items) ' % len(self.targets) + (
-                 ', '.join(self.targets[:2]) + ', ...')
-        else:
-          return ', '.join(self.targets)
+        # The max_length was chosen so that it can fit most of the long
+        # single-target names, while minimizing word wrapping.
+        result = ', '.join(self.targets)
+        max_length = 65
+        if len(result) > max_length:
+          result = result[:max_length] + '...'
+        return result
 
 
 # Copied with some modifications from ninjatracing
@@ -161,7 +158,7 @@
           targets_dict[cmdhash] = target = Target(start, end)
         last_end_seen = end
         target.targets.append(name)
-    return targets_dict.values()
+    return list(targets_dict.values())
 
 
 def GetExtension(target, extra_patterns):
@@ -236,7 +233,8 @@
     length = latest - earliest
     weighted_total = 0.0
 
-    task_start_stop_times.sort()
+    # Sort by the time/type records and ignore |target|
+    task_start_stop_times.sort(key=lambda times: times[:2])
     # Now we have all task start/stop times sorted by when they happen. If a
     # task starts and stops on the same time stamp then the start will come
     # first because of the alphabet, which is important for making this work
@@ -271,7 +269,8 @@
 
     # Warn if the sum of weighted times is off by more than half a second.
     if abs(length - weighted_total) > 500:
-      print('Discrepancy!!! Length = %.3f, weighted total = %.3f' % (
+      print('Warning: Possible corrupt ninja log, results may be '
+            'untrustworthy. Length = %.3f, weighted total = %.3f' % (
             length, weighted_total))
 
     # Print the slowest build steps (by weighted time).